Revision 694
- Date:
- 2018/08/13 17:27:52
- Files:
-
- /utf8/plugins/money/config.proto (Diff) (Checkout)
- /utf8/plugins/money/lib/money/Check.pm (Diff) (Checkout) (copied from /utf8/plugins/money/lib/money/Movement.pm:693)
- /utf8/plugins/money/lib/money/Init.pm (Diff) (Checkout)
- /utf8/plugins/money/lib/money/Movement.pm
- /utf8/plugins/money/lib/money/MovementSection.pm (Diff) (Checkout)
- /utf8/plugins/money/lib/money/Provider/Dreamkas.pm (Diff) (Checkout)
- /utf8/plugins/money/lib/money/SQL/ChecksTable.pm (Diff) (Checkout) (copied from /utf8/plugins/money/lib/money/SQL/MovementsTable.pm:693)
- /utf8/plugins/money/lib/money/SQL/MovementsTable.pm
- /utf8/plugins/money/sql/TOAST/money_checks.sql (Diff) (Checkout) (copied from /utf8/plugins/money/sql/TOAST/money_movement.sql:693)
- /utf8/plugins/money/sql/TOAST/money_movement.sql
Legend:
- Added
- Removed
- Modified
-
utf8/plugins/money/config.proto
11 11 DREAMKAS_ID = 12 12 DREAMKAS_SECRET = 123 13 13 DREAMKAS_CURRENCY_CODE = RUB 14 DREAMKAS_DEVICE_ID = NNNNN # ID кассового аппарата в системе Dreamkas 14 15 DREAMKAS_TAX_MODE = DEFAULT # DEFAULT or SIMPLE or SIMPLE_WO or ENVD or AGRICULT or PATENT 15 16 DREAMKAS_TAX_NDS = NDS_NO_TAX # NDS_NO_TAX or NDS_0 or NDS_10 or NDS_18 or NDS_20 or NDS_10_CALCULATED or NDS_18_CALCULATED 16 17 DREAMKAS_TEST_MODE = 1 # 0 - для боевого режима -
utf8/plugins/money/lib/money/Check.pm
1 package money::Check; 2 3 use base "Contenido::Document"; 4 sub extra_properties 5 { 6 return ( 7 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус тестирования', 8 'cases' => [ 9 [0, 'Реальный чек'], 10 [1, 'Тестовый чек'], 11 ], 12 }, 13 ) 14 } 15 16 sub class_name 17 { 18 return 'Money: онлайн-чек'; 19 } 20 21 sub class_description 22 { 23 return 'Money: онлайн-чек'; 24 } 25 26 sub class_table 27 { 28 return 'money::SQL::ChecksTable'; 29 } 30 31 1; -
utf8/plugins/money/lib/money/Init.pm
12 12 # money::SQL::SomeTable 13 13 # money::SomeClass 14 14 Contenido::Init::load_classes(qw( 15 money::SQL::MovementsTable 16 money::Movement 15 money::SQL::ChecksTable 16 money::Check 17 17 18 18 money::MovementSection 19 19 20 20 money::Provider::Base 21 money::Provider::Dreamkas 21 22 )); 22 23 23 24 sub init { -
utf8/plugins/money/lib/money/Movement.pm
1 package money::Movement; 2 3 use base "Contenido::Document"; 4 sub extra_properties 5 { 6 return ( 7 { 'attr' => 'status', 'type' => 'status', 'rusname' => 'Статус тестирования', 8 'cases' => [ 9 [0, 'Реальный чек'], 10 [1, 'Тестовый чек'], 11 ], 12 }, 13 ) 14 } 15 16 sub class_name 17 { 18 return 'Money: онлайн-чек'; 19 } 20 21 sub class_description 22 { 23 return 'Money: онлайн-чек'; 24 } 25 26 sub class_table 27 { 28 return 'money::SQL::MovementsTable'; 29 } 30 31 1; -
utf8/plugins/money/lib/money/MovementSection.pm
19 19 20 20 sub class_description 21 21 { 22 return 'Money: Секция транзакций';чеков 22 return 'Money: Секция чеков'; 23 23 } 24 24 25 25 1; -
utf8/plugins/money/lib/money/Provider/Dreamkas.pm
74 74 75 75 $self->{currency} = $state->{money}{$prefix."_currency_code"}; 76 76 77 $self->{$base_url} = 'https://'. ($self->{test_mode} ? 'private-anon-f6c2f7b545-kabinet.apiary-mock.com' : 'kabinet.dreamkas.ru').'/api'; 77 $self->{base_url} = 'https://'. ($self->{test_mode} ? 'private-anon-f6c2f7b545-kabinet.apiary-mock.com' : 'kabinet.dreamkas.ru').'/api'; 78 78 $self->{result} = {}; 79 79 80 80 bless $self, $class; … … 189 189 190 190 my $MM; 191 191 if ( exists $opts->{order} ) { 192 $MM = $self->_GetLastMoneyMovement( $opts->{order}->id ); 192 $MM = $self->_GetLastMoneyCheck( $opts->{order}->id ); 193 193 } 194 194 if ( ref $MM && $MM->session_id && $MM->name eq $opts->{type} ) { 195 195 $self->{result}{money_movement} = $MM; 196 196 return $self; 197 197 } 198 198 unless ( $MM ) { 199 $MM = money::Movement->new( $keeper ); 199 $MM = money::Check->new( $keeper ); 200 200 $MM->name( $opts->{type} ); 201 201 $MM->provider( $self->{prefix} ); 202 202 $MM->status( $self->{test_mode} ); … … 220 220 foreach my $bi ( @{$opts->{basket}} ) { 221 221 my $item = $bi->{item}; 222 222 next unless ref $item; 223 my $price = int($bi->{item}->price * 100) 223 my $price = int($bi->{item}->price * 100); 224 224 my $pos = { 225 225 name => $bi->name, 226 226 type => 'COUNTABLE', … … 253 253 my $attributes = {}; 254 254 if ( exists $opts->{email} && $opts->{email} ) { 255 255 if ( ref $opts->{email} ) { 256 $arrtibutes->{email} = $opts->{email}->name; 256 $attributes->{email} = $opts->{email}->name; 257 257 } else { 258 $arrtibutes->{email} = $opts->{email}; 258 $attributes->{email} = $opts->{email}; 259 259 } 260 260 } 261 261 if ( exists $opts->{phone} && $opts->{phone} ) { 262 262 if ( ref $opts->{phone} ) { 263 $arrtibutes->{phone} = $opts->{phone}->name; 263 $attributes->{phone} = $opts->{phone}->name; 264 264 } else { 265 $arrtibutes->{phone} = $opts->{phone}; 265 $attributes->{phone} = $opts->{phone}; 266 266 } 267 267 } 268 268 $data->{attributes} = $attributes; … … 286 286 $data->{payments}{type} = 'CASH'; 287 287 } 288 288 289 my $api_url = '/api/receipts'; 289 my $api_url = 'receipts'; 290 290 291 291 $self->_MakeRequest( $api_url, 'post', $data ); 292 292 if ( $self->{result}{code} == 202 ) { … … 346 346 } elsif ( exists $opts->{money_movement} ) { 347 347 $MM = $opts->{money_movement}; 348 348 } elsif ( $opts->{operation_id} ) { 349 ($MM) = $self->_GetMMByOperationId( $opts->{operation_id} ); 349 ($MM) = $self->_GetCheckByOperationId( $opts->{operation_id} ); 350 350 } 351 351 unless ( ref $MM ) { 352 352 $self->{result}{error} = 'Не найден объект "движение денежных средств". Проверьте входные параметры'; 353 353 return $self; 354 354 } 355 355 356 my $api_url = '/api/operations/'.$MM->session_id; 356 my $api_url = 'operations/'.$MM->session_id; 357 357 358 358 $self->_MakeRequest( $api_url, 'get' ); 359 359 if ( $self->{result}{code} == 200 ) { … … 388 388 $body = encode_json( $body ); 389 389 } 390 390 391 my $req = URI->new( $self->{host}.($url =~ /^\// ? '' : '/').$url ); 391 my $req = URI->new( $self->{base_url}.($url =~ /^\// ? '' : '/').$url ); 392 392 my $res; 393 393 if ( $type eq 'post' ) { 394 394 $res = $ua->post( $req, Content => $body ); … … 401 401 code => $res->code, 402 402 status => $res->status_line, 403 403 content => JSON::XS->new->decode( $res->decoded_content ), 404 } 404 }; 405 405 return $self; 406 406 } 407 407 408 sub _GetLastMoneyMovement { 408 sub _GetLastMoneyCheck { 409 409 my $self = shift; 410 410 my $order_id = shift; 411 411 my ($mm) = $keeper->get_documents( 412 class => 'money::Movement', 412 class => 'money::Check', 413 413 limit => 1, 414 order_id => $order_id 414 provider => $self->{prefix}, 415 order_id => $order_id, 415 416 order_by => 'id desc', 416 417 ); 417 418 return $mm; 418 419 } 419 420 420 sub _GetMMByOperationId { 421 sub _GetCheckByOperationId { 421 422 my $self = shift; 422 423 my $op_id = shift; 423 424 my ($mm) = $keeper->get_documents( 424 class => 'money::Movement', 425 class => 'money::Check', 425 426 limit => 1, 427 provider => $self->{prefix}, 426 428 session_id => $op_id, 427 429 ); 428 430 return $mm; -
utf8/plugins/money/lib/money/SQL/ChecksTable.pm
1 package money::SQL::ChecksTable; 2 3 use base 'SQL::DocumentTable'; 4 5 sub db_table 6 { 7 return 'money_movements'; 8 } 9 10 sub db_id_sequence { 11 return 'money_movements_id_seq'; 12 } 13 14 sub available_filters { 15 my @available_filters = qw( 16 17 _class_filter 18 _status_filter 19 _in_id_filter 20 _id_filter 21 _name_filter 22 _class_excludes_filter 23 _sfilter_filter 24 _excludes_filter 25 _datetime_filter 26 _date_equal_filter 27 _date_filter 28 _previous_days_filter 29 30 _provider_filter 31 _session_id_filter 32 _order_id_filter 33 _success_filter 34 _name_exact_filter 35 ); 36 37 return \@available_filters; 38 } 39 40 # ---------------------------------------------------------------------------- 41 # Свойства храним в массивах, потому что порядок важен! 42 # Это общие свойства - одинаковые для всех документов. 43 # 44 # attr - обязательный параметр, название атрибута; 45 # type - тип аттрибута, требуется для отображдения; 46 # rusname - русское название, опять же требуется для отображения; 47 # hidden - равен 1, когда 48 # readonly - инициализации при записи только без изменения в дальнейшем 49 # db_field - поле в таблице 50 # default - значение по умолчанию (поле всегда имеет это значение) 51 # ---------------------------------------------------------------------------- 52 sub required_properties 53 { 54 my $self = shift; 55 56 my @parent_properties = grep { $_->{attr} ne 'sections' } $self->SUPER::required_properties; 57 return ( 58 @parent_properties, 59 { 60 'attr' => 'provider', 61 'type' => 'string', 62 'rusname' => 'Провайдер', 63 'db_field' => 'provider', 64 'db_type' => 'text', 65 }, 66 { 67 'attr' => 'session_id', 68 'type' => 'string', 69 'rusname' => 'Ключ сессии', 70 'db_field' => 'session_id', 71 'db_type' => 'text', 72 }, 73 { # ID заказа 74 'attr' => 'order_id', 75 'type' => 'integer', 76 'rusname' => 'ID заказа', 77 'db_field' => 'order_id', 78 'db_type' => 'integer', 79 'db_opts' => "not null", 80 }, 81 { 82 'attr' => 'currency_code', 83 'type' => 'string', 84 'rusname' => 'ID валюты', 85 'db_field' => 'currency_code', 86 'db_type' => 'varchar(4)', 87 }, 88 { 89 'attr' => 'sum', 90 'type' => 'string', 91 'rusname' => 'Сумма чека', 92 'db_field' => 'sum', 93 'db_type' => 'float', 94 }, 95 { # Результат транзакции 96 'attr' => 'success', 97 'type' => 'checkbox', 98 'rusname' => 'Транзакция прошла успешно', 99 'db_field' => 'success', 100 'db_type' => 'smallint', 101 'db_opts' => "default 0", 102 }, 103 ); 104 } 105 106 107 ########### FILTERS DESCRIPTION ############################################################################### 108 sub _order_id_filter { 109 my ($self,%opts)=@_; 110 return undef unless ( exists $opts{order_id} ); 111 return &SQL::Common::_generic_int_filter('d.order_id', $opts{order_id}); 112 } 113 114 sub _success_filter { 115 my ($self,%opts)=@_; 116 return undef unless ( exists $opts{success} ); 117 return &SQL::Common::_generic_int_filter('d.success', $opts{success}); 118 } 119 120 sub _provider_filter { 121 my ($self,%opts)=@_; 122 return undef unless ( exists $opts{provider} ); 123 return &SQL::Common::_generic_text_filter('d.provider', $opts{provider}); 124 } 125 126 sub _session_id_filter { 127 my ($self,%opts)=@_; 128 return undef unless ( exists $opts{session_id} ); 129 return &SQL::Common::_generic_int_filter('d.session_id', $opts{session_id}); 130 } 131 132 sub _name_exact_filter { 133 my ($self,%opts)=@_; 134 return undef unless ( exists $opts{name_exact} ); 135 return &SQL::Common::_generic_text_filter('d.name', $opts{name_exact}); 136 } 137 138 1; -
utf8/plugins/money/lib/money/SQL/MovementsTable.pm
1 package money::SQL::MovementsTable; 2 3 use base 'SQL::DocumentTable'; 4 5 sub db_table 6 { 7 return 'money_movements'; 8 } 9 10 sub db_id_sequence { 11 return 'money_movements_id_seq'; 12 } 13 14 sub available_filters { 15 my @available_filters = qw( 16 17 _class_filter 18 _status_filter 19 _in_id_filter 20 _id_filter 21 _name_filter 22 _class_excludes_filter 23 _sfilter_filter 24 _excludes_filter 25 _datetime_filter 26 _date_equal_filter 27 _date_filter 28 _previous_days_filter 29 30 _provider_filter 31 _session_id_filter 32 _order_id_filter 33 _success_filter 34 _name_exact_filter 35 ); 36 37 return \@available_filters; 38 } 39 40 # ---------------------------------------------------------------------------- 41 # Свойства храним в массивах, потому что порядок важен! 42 # Это общие свойства - одинаковые для всех документов. 43 # 44 # attr - обязательный параметр, название атрибута; 45 # type - тип аттрибута, требуется для отображдения; 46 # rusname - русское название, опять же требуется для отображения; 47 # hidden - равен 1, когда 48 # readonly - инициализации при записи только без изменения в дальнейшем 49 # db_field - поле в таблице 50 # default - значение по умолчанию (поле всегда имеет это значение) 51 # ---------------------------------------------------------------------------- 52 sub required_properties 53 { 54 my $self = shift; 55 56 my @parent_properties = grep { $_->{attr} ne 'sections' } $self->SUPER::required_properties; 57 return ( 58 @parent_properties, 59 { 60 'attr' => 'provider', 61 'type' => 'string', 62 'rusname' => 'Провайдер', 63 'db_field' => 'provider', 64 'db_type' => 'text', 65 }, 66 { 67 'attr' => 'session_id', 68 'type' => 'string', 69 'rusname' => 'Ключ сессии', 70 'db_field' => 'session_id', 71 'db_type' => 'text', 72 }, 73 { # ID заказа 74 'attr' => 'order_id', 75 'type' => 'integer', 76 'rusname' => 'ID заказа', 77 'db_field' => 'order_id', 78 'db_type' => 'integer', 79 'db_opts' => "not null", 80 }, 81 { 82 'attr' => 'currency_code', 83 'type' => 'string', 84 'rusname' => 'ID валюты', 85 'db_field' => 'currency_code', 86 'db_type' => 'varchar(4)', 87 }, 88 { 89 'attr' => 'sum', 90 'type' => 'string', 91 'rusname' => 'Сумма чека', 92 'db_field' => 'sum', 93 'db_type' => 'float', 94 }, 95 { # Результат транзакции 96 'attr' => 'success', 97 'type' => 'checkbox', 98 'rusname' => 'Транзакция прошла успешно', 99 'db_field' => 'success', 100 'db_type' => 'smallint', 101 'db_opts' => "default 0", 102 }, 103 ); 104 } 105 106 107 ########### FILTERS DESCRIPTION ############################################################################### 108 sub _order_id_filter { 109 my ($self,%opts)=@_; 110 return undef unless ( exists $opts{order_id} ); 111 return &SQL::Common::_generic_int_filter('d.order_id', $opts{order_id}); 112 } 113 114 sub _success_filter { 115 my ($self,%opts)=@_; 116 return undef unless ( exists $opts{success} ); 117 return &SQL::Common::_generic_int_filter('d.success', $opts{success}); 118 } 119 120 sub _provider_filter { 121 my ($self,%opts)=@_; 122 return undef unless ( exists $opts{provider} ); 123 return &SQL::Common::_generic_text_filter('d.provider', $opts{provider}); 124 } 125 126 sub _session_id_filter { 127 my ($self,%opts)=@_; 128 return undef unless ( exists $opts{session_id} ); 129 return &SQL::Common::_generic_int_filter('d.session_id', $opts{session_id}); 130 } 131 132 sub _name_exact_filter { 133 my ($self,%opts)=@_; 134 return undef unless ( exists $opts{name_exact} ); 135 return &SQL::Common::_generic_text_filter('d.name', $opts{name_exact}); 136 } 137 138 1; -
utf8/plugins/money/sql/TOAST/money_checks.sql
1 create sequence money_checks_id_seq; 2 select setval('money_checks_id_seq', 1, true); 3 4 create table money_checks 5 ( 6 id integer not null primary key default nextval('public.documents_id_seq'::text), 7 class text not null, 8 ctime timestamp not null default now(), 9 mtime timestamp not null default now(), 10 dtime timestamp not null default now(), 11 status smallint not null default 0, 12 provider text, 13 session_id text, 14 name text, 15 order_id integer not null, 16 currency_code varchar(4), 17 sum float, 18 success smallint default 0, 19 data text 20 ); 21 CREATE INDEX money_checks_sessions ON money_checks USING btree (provider, session_id) WHERE session_id is not null; 22 CREATE INDEX money_checks_orders ON money_checks USING btree (order_id); -
utf8/plugins/money/sql/TOAST/money_movement.sql
1 create sequence money_movements_id_seq; 2 select setval('money_movements_id_seq', 1, true); 3 4 create table money_movements 5 ( 6 id integer not null primary key default nextval('public.documents_id_seq'::text), 7 class text not null, 8 ctime timestamp not null default now(), 9 mtime timestamp not null default now(), 10 dtime timestamp not null default now(), 11 status smallint not null default 0, 12 provider text, 13 session_id text, 14 name text, 15 order_id integer not null, 16 currency_code varchar(4), 17 sum float, 18 success smallint default 0, 19 data text 20 ); 21 CREATE INDEX money_movements_sessions ON money_movements USING btree (provider, session_id) WHERE session_id is not null; 22 CREATE INDEX money_movements_orders ON money_movements USING btree (order_id);