Revision 358
Date:
2013/06/11 08:56:08
Author:
ahitrov
Revision Log:
Initial plugin import
Files:
Legend:
Added
Removed
Modified
utf8/plugins/payments/comps/contenido/payments/autohandler
1
<%init>
2
3
$r->content_type('text/html');
4
$m->call_next();
5
6
</%init>
utf8/plugins/payments/comps/contenido/payments/dhandler
1
<& $call, %ARGS &>
2
<%init>
3
4
my $call;
5
if ( $r->uri eq '/contenido/payments/' ) {
6
$call = 'index.html';
7
} else {
8
&abort404;
9
}
10
11
</%init>
utf8/plugins/payments/comps/contenido/payments/index.html
1
<& "/contenido/components/header.msn" &>
2
<& "/contenido/components/naviline.msn" &>
3
4
<p>PLugin [payments]</p>
5
6
</body>
7
</html>
utf8/plugins/payments/comps/www/payment.backend/moneta_check.xml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<MNT_RESPONSE>
3
<MNT_ID><% $MNT_ID %></MNT_ID>
4
<MNT_TRANSACTION_ID><% $MNT_TRANSACTION_ID %></MNT_TRANSACTION_ID>
5
<MNT_RESULT_CODE><% $reply_code %></MNT_RESULT_CODE>
6
% if ( ref $last ) {
7
<MNT_DESCRIPTION><% $last->name %></MNT_DESCRIPTION>
8
% }
9
<MNT_AMOUNT><% $MNT_AMOUNT %></MNT_AMOUNT>
10
<MNT_SIGNATURE><% $reply_md5 %></MNT_SIGNATURE>
11
<%doc>
12
<MNT_ATTRIBUTES>
13
<ATTRIBUTE>
14
<KEY></KEY>
15
<VALUE></VALUE>
16
</ATTRIBUTE>
17
</MNT_ATTRIBUTES>
18
</%doc>
19
</MNT_RESPONSE>
20
<%once>
21
22
use Digest::MD5;
23
24
</%once>
25
<%args>
26
27
$MNT_COMMAND => ''
28
$MNT_ID => undef
29
$MNT_TRANSACTION_ID => undef
30
$MNT_OPERATION_ID => ''
31
$MNT_AMOUNT => ''
32
$MNT_CURRENCY_CODE => undef
33
$MNT_TEST_MODE => 0
34
$MNT_SIGNATURE => undef
35
$MNT_USER => undef
36
$MNT_CORRACCOUNT => undef
37
$MNT_CUSTOM1 => undef
38
$MNT_CUSTOM2 => undef
39
$MNT_CUSTOM3 => undef
40
41
</%args>
42
<%init>
43
44
warn Dumper \%ARGS if $DEBUG;
45
unless ( $MNT_ID && $MNT_TRANSACTION_ID && $MNT_CURRENCY_CODE ) {
46
$m->out('FAIL');
47
return;
48
}
49
50
my $str = $MNT_COMMAND . $MNT_ID . $MNT_TRANSACTION_ID . $MNT_OPERATION_ID . $MNT_AMOUNT . $MNT_CURRENCY_CODE . $MNT_TEST_MODE . $state->{monetaru}->{moneta_sig_code};
51
my $md5 = Digest::MD5::md5_hex ( $str );
52
warn "MD5 Check: $md5\n" if $DEBUG;
53
unless ( $MNT_SIGNATURE eq $md5 ) {
54
$m->out('FAIL');
55
return;
56
}
57
58
my $reply_code;
59
my $last = $keeper->{monetaru}->check( $MNT_TRANSACTION_ID );
60
if ( ref $last ) {
61
my $sum = sprintf("%.2f", $last->sum);
62
if ( $last->name eq 'cancel' ) {
63
$reply_code = 500;
64
} elsif ( !$MNT_AMOUNT && $last->name =~ /(create|reform)/ ) {
65
$MNT_AMOUNT = $last->sum;
66
$reply_code = 100;
67
} elsif ( $last->name =~ /(create|reform)/ && $sum ne $MNT_AMOUNT ) {
68
$MNT_AMOUNT = $last->sum;
69
$reply_code = 100;
70
} elsif ( $last->name eq 'suspend' ) {
71
$reply_code = 302;
72
}
73
} else {
74
$reply_code = 500;
75
}
76
77
unless ( $reply_code ) {
78
my ($obj) = $keeper->get_documents(
79
class => 'monetaru::Transaction',
80
order_id => $MNT_TRANSACTION_ID,
81
limit => 1,
82
);
83
if ( ref $obj ) {
84
$reply_code = 200;
85
} else {
86
$reply_code = 402;
87
}
88
}
89
warn "CHECK_URL: Reply code = [$reply_code]\n" if $DEBUG;
90
91
$str = $reply_code . $MNT_ID . $MNT_TRANSACTION_ID . $state->{monetaru}->{moneta_sig_code};
92
my $reply_md5 = Digest::MD5::md5_hex ( $str );
93
warn "Reply MD5: $reply_md5\n" if $DEBUG;
94
95
</%init>
utf8/plugins/payments/comps/www/payment.backend/moneta_pay.txt
1
SUCCESS
2
<%once>
3
4
use Digest::MD5;
5
6
</%once>
7
<%args>
8
9
$MNT_ID => undef
10
$MNT_TRANSACTION_ID => undef
11
$MNT_OPERATION_ID => undef
12
$MNT_AMOUNT => 0
13
$MNT_CURRENCY_CODE => undef
14
$MNT_TEST_MODE => 0
15
$MNT_SIGNATURE => undef
16
$MNT_USER => undef
17
$MNT_CORRACCOUNT => undef
18
$MNT_CUSTOM1 => undef
19
$MNT_CUSTOM2 => undef
20
$MNT_CUSTOM3 => undef
21
22
</%args>
23
<%init>
24
25
warn Dumper \%ARGS if $DEBUG;
26
unless ( $MNT_ID && $MNT_TRANSACTION_ID && $MNT_OPERATION_ID && $MNT_AMOUNT && $MNT_CURRENCY_CODE ) {
27
$m->out('FAIL');
28
return;
29
}
30
31
my ($obj) = $keeper->get_documents(
32
class => 'monetaru::Transaction',
33
operation_id => $MNT_OPERATION_ID,
34
order_id => $MNT_TRANSACTION_ID,
35
limit => 1,
36
);
37
my $str = $MNT_ID . $MNT_TRANSACTION_ID . $MNT_OPERATION_ID . $MNT_AMOUNT . $MNT_CURRENCY_CODE . $MNT_TEST_MODE . $state->{monetaru}->{moneta_sig_code};
38
my $md5 = Digest::MD5::md5_hex ( $str );
39
unless ( $MNT_SIGNATURE eq $md5 ) {
40
$m->out('FAIL');
41
return;
42
}
43
44
unless ( $obj ) {
45
$obj = monetaru::Transaction->new( $keeper );
46
$obj->status( $MNT_TEST_MODE || 0 );
47
$obj->account_id( $MNT_ID );
48
$obj->order_id( $MNT_TRANSACTION_ID );
49
$obj->operation_id( $MNT_OPERATION_ID );
50
$obj->sum( $MNT_AMOUNT );
51
$obj->currency_code( $MNT_CURRENCY_CODE );
52
$obj->account_user( $MNT_USER );
53
$obj->account_corr( $MNT_CORRACCOUNT );
54
$obj->payment_system( $ARGS{'paymentSystem.unitId'} );
55
$obj->name( $MNT_CUSTOM1 );
56
$obj->custom1( $MNT_CUSTOM1 );
57
$obj->custom2( $MNT_CUSTOM2 );
58
$obj->custom3( $MNT_CUSTOM3 );
59
$obj->store;
60
}
61
62
</%init>
utf8/plugins/payments/comps/www/payment.backend/moneta_pay.xml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<MNT_RESPONSE>
3
<MNT_ID><% $MNT_ID %></MNT_ID>
4
<MNT_TRANSACTION_ID><% $MNT_TRANSACTION_ID %></MNT_TRANSACTION_ID>
5
<MNT_RESULT_CODE><% $reply_code %></MNT_RESULT_CODE>
6
<MNT_SIGNATURE><% $reply_md5 %></MNT_SIGNATURE>
7
<%doc>
8
<MNT_ATTRIBUTES>
9
<ATTRIBUTE>
10
<KEY></KEY>
11
<VALUE></VALUE>
12
</ATTRIBUTE>
13
</MNT_ATTRIBUTES>
14
</%doc>
15
</MNT_RESPONSE>
16
<%once>
17
18
use Digest::MD5;
19
20
</%once>
21
<%args>
22
23
$MNT_ID => undef
24
$MNT_TRANSACTION_ID => undef
25
$MNT_OPERATION_ID => undef
26
$MNT_AMOUNT => ''
27
$MNT_CURRENCY_CODE => undef
28
$MNT_TEST_MODE => 0
29
$MNT_SIGNATURE => undef
30
$MNT_USER => undef
31
$MNT_CORRACCOUNT => undef
32
$MNT_CUSTOM1 => undef
33
$MNT_CUSTOM2 => undef
34
$MNT_CUSTOM3 => undef
35
36
</%args>
37
<%init>
38
39
warn Dumper \%ARGS if $DEBUG;
40
unless ( $MNT_ID && $MNT_TRANSACTION_ID && $MNT_OPERATION_ID && $MNT_AMOUNT && $MNT_CURRENCY_CODE ) {
41
$m->out('FAIL');
42
return;
43
}
44
45
my $str = $MNT_ID . $MNT_TRANSACTION_ID . $MNT_OPERATION_ID . $MNT_AMOUNT . $MNT_CURRENCY_CODE . $MNT_TEST_MODE . $state->{monetaru}->{moneta_sig_code};
46
my $md5 = Digest::MD5::md5_hex ( $str );
47
unless ( $MNT_SIGNATURE eq $md5 ) {
48
$m->out('FAIL');
49
return;
50
}
51
52
my $reply_code;
53
my $last = $keeper->{monetaru}->check( $MNT_TRANSACTION_ID );
54
if ( ref $last ) {
55
my $sum = sprintf("%.2f", $last->sum);
56
if ( $last->name eq 'cancel' ) {
57
$reply_code = 500;
58
} elsif ( $last->name eq 'suspend' ) {
59
$reply_code = 500;
60
}
61
} else {
62
$reply_code = 500;
63
}
64
65
unless ( $reply_code ) {
66
my ($obj) = $keeper->get_documents(
67
class => 'monetaru::Transaction',
68
operation_id => $MNT_OPERATION_ID,
69
order_id => $MNT_TRANSACTION_ID,
70
limit => 1,
71
);
72
73
unless ( $obj ) {
74
$obj = monetaru::Transaction->new( $keeper );
75
$obj->status( $MNT_TEST_MODE || 0 );
76
$obj->account_id( $MNT_ID );
77
$obj->order_id( $MNT_TRANSACTION_ID );
78
$obj->operation_id( $MNT_OPERATION_ID );
79
$obj->sum( $MNT_AMOUNT );
80
$obj->currency_code( $MNT_CURRENCY_CODE );
81
$obj->account_user( $MNT_USER );
82
$obj->account_corr( $MNT_CORRACCOUNT );
83
$obj->payment_system( $ARGS{'paymentSystem.unitId'} );
84
$obj->name( $MNT_CUSTOM1 );
85
$obj->custom1( $MNT_CUSTOM1 );
86
$obj->custom2( $MNT_CUSTOM2 );
87
$obj->custom3( $MNT_CUSTOM3 );
88
$obj->store;
89
}
90
if ( $obj->id ) {
91
$reply_code = 200;
92
} else {
93
$reply_code = 100;
94
}
95
}
96
97
$str = $reply_code . $MNT_ID . $MNT_TRANSACTION_ID . $state->{monetaru}->{moneta_sig_code};
98
my $reply_md5 = Digest::MD5::md5_hex ( $str );
99
100
</%init>
utf8/plugins/payments/comps/www/payment.backend/xsolla_v2_pay.xml
1
<?xml version="1.0" encoding="UTF-8"?>
2
<response>
3
<result><% $code %></result>
4
<description><% $codes{$code} %></description>
5
<fields>
6
<id><% $id %></id>
7
<order><% $v1 %></order>
8
<amount><% $amount %></amount>
9
<currency><% $currency %></currency>
10
<datetime><% $datetime %></datetime>
11
<sign><% $sign %></sign>
12
</fields>
13
</response>
14
<%doc>
15
16
сommand Признак того, что идет оповещение о платеже
17
id Уникальный id операции в системе «Иксолла»
18
v1 Уникальный идентификатор заказа, полученный от проекта. В XML-ответе значение этого параметра следует передававть в параметре order.
19
amount Стоимость заказа. Разделитель “.” (2 знака после точки)
20
currency Валюта заказа. Используется трехбуквенное обозначение валюты согласно стандарту ISO 4217
21
datetime Дата в формате ГГГГММДДЧЧММСС
22
test Признак тестовой транзакции. test=1 – система проводит тестовую транзакцию. Реального платежа не было. test=0 – реальный платеж
23
sign Подпись для предотвращения несанкционированного доступа
24
user_sum Размер платежа, совершенного пользователем. Разделитель “.” (2 знака после точки)
25
user_currency Валюта платежа, совершенного пользователем. Используется трехбуквенное обозначение валюты согласно стандарту ISO 4217
26
transfer_sum Сумма выплаты проекту. Разделитель “.” (2 знака после точки)
27
transfer_currency Валюта выплаты проекту. Используется трехбуквенное обозначение валюты согласно стандарту ISO 4217
28
pid Идентификационный номер платежной системы
29
id_geotype id валюты платежной системы
30
31
</%doc>
32
<%once>
33
34
use Digest::MD5;
35
my @valid_ips = qw( 94.103.26.178 94.103.26.181 159.255.220.254 );
36
my %codes = (
37
'0' => 'Success',
38
'10' => 'Another delivery attempt',
39
'20' => 'Wrong parameters',
40
'30' => 'Temporary error',
41
'40' => 'Fatal error',
42
);
43
44
</%once>
45
<%args>
46
47
$id => undef
48
$v1 => ''
49
$v2 => ''
50
$v3 => ''
51
$amount => undef
52
$currency => undef
53
$datetime => undef
54
$test => undef
55
$sign => undef
56
$user_sum => undef
57
$user_currency => undef
58
$transfer_sum => undef
59
$transfer_currency => undef
60
$pid => undef
61
$id_geotype => undef
62
63
</%args>
64
<%init>
65
66
warn Dumper \%ARGS if $DEBUG;
67
68
my $str = $v1.$v2.$v3.$amount.$currency.$id.$state->{payments}{xsolla_app_secret};
69
my $md5 = Digest::MD5::md5_hex ( $str );
70
warn "MD5 Check: $md5\n" if $DEBUG;
71
72
my $code = 0;
73
my $ip = $r->header_in('X-Real-IP');
74
warn "From IP=$ip\n";
75
my $transaction;
76
if ( $md5 eq $sign && grep { $ip eq $_ } @valid_ips ) {
77
my $last = $keeper->{payments}->check( $v1 );
78
if ( $last->name eq 'cancel' ) {
79
$code = 40;
80
} elsif ( $last->name eq 'suspend' ) {
81
$code = 20;
82
}
83
unless ( $code ) {
84
($transaction) = $keeper->get_documents(
85
class => 'payments::Transaction',
86
order_id => $v1,
87
operation_id => $id,
88
provider => 'xsolla',
89
limit => 1,
90
);
91
if ( ref $transaction ) {
92
$code = 10;
93
} else {
94
my $dt = $datetime =~ /^(\d{4})(\d{2})(\d{2})(\d{2})(\d{2})(\d{2})/ ? "$1-$2-$3 $4:$5:$6" : '';
95
$transaction = payments::Transaction->new( $keeper );
96
$transaction->status( $test || 0 );
97
$transaction->provider( 'xsolla' );
98
$transaction->order_id( $v1 );
99
$transaction->operation_id( $id );
100
$transaction->sum( $amount );
101
$transaction->currency_code( $currency );
102
$transaction->dtime( $dt ) if $dt;
103
$transaction->custom1( $v2 );
104
$transaction->custom2( $v3 );
105
$transaction->name( $v2 || $v3 );
106
$transaction->store();
107
}
108
}
109
} else {
110
$code = 20;
111
}
112
113
</%init>
utf8/plugins/payments/config.proto
1
#############################################################################
2
#
3
# Параметры данного шаблона необходимо ВРУЧНУЮ добавить в config.mk проекта
4
# и привести в соответствие с требованиями проекта
5
#
6
#############################################################################
7
PLUGINS += payments
8
9
# Moneta.ru
10
############################################################
11
MNT_ID =
12
MNT_SECRET =
13
MNT_CURRENCY_CODE = RUB
14
MNT_TEST_MODE = 1 # 0 - для боевого режима
15
# Для подтверждения целостности
16
MNT_SIG_CODE =
17
18
REWRITE += MNT_ID MNT_SECRET MNT_CURRENCY_CODE MNT_TEST_MODE MNT_SIG_CODE
19
############################################################
20
# /Moneta.ru
21
22
23
# xsolla.com
24
############################################################
25
XSO_ID =
26
XSO_SECRET =
27
XSO_CURRENCY_CODE = RUB
28
XSO_TEST_MODE = 1 # 0 - для боевого режима
29
# Для подтверждения целостности
30
XSO_SIG_CODE =
31
32
REWRITE += XSO_ID XSO_SECRET XSO_CURRENCY_CODE XSO_TEST_MODE XSO_SIG_CODE
33
############################################################
34
# /xsolla.com
35
utf8/plugins/payments/lib/payments/Apache.pm
1
package payments::Apache;
2
3
use strict;
4
use warnings 'all';
5
6
use payments::State;
7
use Contenido::Globals;
8
9
10
sub child_init {
11
# встраиваем keeper плагина в keeper проекта
12
$keeper->{payments} = payments::Keeper->new($state->payments);
13
}
14
15
sub request_init {
16
}
17
18
sub child_exit {
19
}
20
21
1;
utf8/plugins/payments/lib/payments/Init.pm
1
package payments::Init;
2
3
use strict;
4
use warnings 'all';
5
6
use Contenido::Globals;
7
use payments::Apache;
8
use payments::Keeper;
9
10
use payments::Provider::Base;
11
12
# загрузка всех необходимых плагину классов
13
# payments::SQL::SomeTable
14
# payments::SomeClass
15
Contenido::Init::load_classes(qw(
16
payments::SQL::TransactionsTable
17
payments::Transaction
18
19
payments::SQL::OperationsTable
20
payments::Operation
21
22
payments::TransactionSection
23
24
payments::Provider::Base
25
payments::Provider::Moneta
26
payments::Provider::Xsolla
27
));
28
29
sub init {
30
push @{ $state->{'available_documents'} }, qw( payments::Transaction payments::Operation );
31
push @{ $state->{'available_sections'} }, qw( payments::TransactionSection );
32
0;
33
}
34
35
1;
utf8/plugins/payments/lib/payments/Keeper.pm
1
package payments::Keeper;
2
3
use strict;
4
use warnings 'all';
5
use base qw(Contenido::Keeper);
6
7
8
use Contenido::Globals;
9
10
sub add {
11
my $self = shift;
12
my (%opts) = @_;
13
14
return undef unless $opts{type} && ( $opts{order} && ref $opts{order} || $opts{uid} && $opts{order} && $opts{sum});
15
return undef unless $opts{type} =~ /^(create|suspend|cancel|append|reform)$/;
16
17
my $op = payments::Operation->new( $keeper );
18
$op->status(1);
19
$op->name( $opts{type} );
20
if ( ref $opts{order} ) {
21
$op->uid( $opts{order}->uid );
22
$op->order_id( $opts{order}->id );
23
$op->sum( $opts{order}->sum_total );
24
} else {
25
$op->uid( $opts{uid} );
26
$op->order_id( $opts{order} );
27
$op->sum( $opts{sum} );
28
}
29
$op->store;
30
31
return $op;
32
}
33
34
35
sub check {
36
my $self = shift;
37
my $order_id = shift;
38
return undef unless $order_id;
39
40
my $ops = $keeper->get_documents(
41
class => 'payments::Operation',
42
order_id => $order_id,
43
order_by => 'ctime',
44
return_mode => 'array_ref',
45
);
46
if ( ref $ops eq 'ARRAY' && @$ops ) {
47
return $ops->[-1];
48
}
49
return undef;
50
}
51
52
53
1;
utf8/plugins/payments/lib/payments/Operation.pm
1
package payments::Operation;
2
3
use base "Contenido::Document";
4
sub extra_properties
5
{
6
return (
7
{ 'attr' => 'name', 'type' => 'status', 'rusname' => 'Тип операции',
8
'cases' => [
9
['create', 'Заказ создан'],
10
['suspend', 'Заказ заморожен'],
11
['reform', 'Заказ изменен'],
12
['append', 'Доплата по заказу'],
13
['cancel', 'Заказ отменен'],
14
],
15
},
16
)
17
}
18
19
sub class_name
20
{
21
return 'Payments: операция с заказом';
22
}
23
24
sub class_description
25
{
26
return 'Payments: операция с заказом';
27
}
28
29
sub class_table
30
{
31
return 'payments::SQL::OperationsTable';
32
}
33
34
1;
utf8/plugins/payments/lib/payments/Provider/Base.pm
1
package payments::Provider::Base;
2
3
use strict;
4
use warnings 'all';
5
use Contenido::Globals;
6
use payments::Keeper;
7
8
9
sub new {
10
my ($proto, %params) = @_;
11
my $class = ref($proto) || $proto;
12
my $self = {};
13
my $prefix = $class =~ /\:\:(\w+)$/ ? lc($1) : undef;
14
return unless $prefix;
15
16
$self->{payment_system} = $prefix;
17
$self->{app_id} = $state->{payments}->{$prefix."_app_id"};
18
$self->{secret} = $state->{payments}->{$prefix."_app_secret"};
19
$self->{currency} = $state->{payments}->{$prefix."_currency_code"};
20
$self->{test_mode} = $state->{payments}->{$prefix."_test_mode"};
21
22
bless $self, $class;
23
24
return $self;
25
}
26
27
28
sub id {
29
my $self = shift;
30
return $self->{app_id};
31
}
32
33
sub app_id {
34
my $self = shift;
35
return $self->{app_id};
36
}
37
38
sub secret {
39
my $self = shift;
40
return $self->{secret};
41
}
42
43
sub test_mode {
44
my $self = shift;
45
return $self->{test_mode};
46
}
47
48
sub currency {
49
my $self = shift;
50
return $self->{currency};
51
}
52
53
sub currency_code {
54
my $self = shift;
55
return $self->{currency};
56
}
57
58
sub payment_system {
59
my $self = shift;
60
return $self->{payment_system};
61
}
62
63
1;
utf8/plugins/payments/lib/payments/Provider/Moneta.pm
1
package payments::Provider::Base;
2
3
use strict;
4
use warnings 'all';
5
6
use base 'payments::Provider::Base';
7
use Contenido::Globals;
8
use payments::Keeper;
9
use Digest::MD5;
10
use Data::Dumper;
11
12
sub get_form {
13
my $self = shift;
14
my (%opts) = @_;
15
my $id = delete $opts{id};
16
return unless $id;
17
my $sum = delete $opts{sum};
18
return unless $sum;
19
20
$sum = $sum =~ /\d+\.\d{2}/ ? $sum : sprintf( "%.2f", $sum );
21
22
my %fields = (
23
'method' => 'post',
24
'action' => 'https://www.moneta.ru/assistant.htm',
25
'visible' => [
26
{ type => 'submit', value => $opts{submit} || 'Оплатить' },
27
],
28
'hidden' => [
29
{ name => 'MNT_ID', value => $state->{payments}{moneta_app_id} },
30
{ name => 'MNT_TRANSACTION_ID', value => $id },
31
{ name => 'MNT_CURRENCY_CODE', value => $state->{payments}{moneta_currency_code} },
32
{ name => 'MNT_AMOUNT', value => $sum },
33
],
34
);
35
if ( $state->{payments}{moneta_test_mode} ) {
36
push @{$fields{hidden}}, { name => 'MNT_TEST_MODE', value => 1 }
37
}
38
if ( $opts{success} ) {
39
push @{$fields{hidden}}, { name => 'MNT_SUCCESS_URL', value => $opts{success} }
40
}
41
if ( $opts{fail} ) {
42
push @{$fields{hidden}}, { name => 'MNT_FAIL_URL', value => $opts{fail} }
43
}
44
if ( $state->{payments}{moneta_sig_code} ) {
45
my $str = $state->{payments}{moneta_app_id}.$id.$sum.$state->{payments}{moneta_currency_code}.$state->{payments}{moneta_test_mode}.$state->{payments}{moneta_sig_code};
46
my $md5 = Digest::MD5::md5_hex ( $str );
47
push @{$fields{hidden}}, { name => 'MNT_SIGNATURE', value => $md5 }
48
}
49
50
if ( exists $opts{custom1} ) {
51
push @{$fields{hidden}}, { name => 'MNT_CUSTOM1', value => $opts{custom1} }
52
}
53
if ( exists $opts{custom2} ) {
54
push @{$fields{hidden}}, { name => 'MNT_CUSTOM2', value => $opts{custom2} }
55
}
56
if ( exists $opts{custom3} ) {
57
push @{$fields{hidden}}, { name => 'MNT_CUSTOM3', value => $opts{custom3} }
58
}
59
60
return \%fields;
61
}
62
63
64
1;
utf8/plugins/payments/lib/payments/Provider/Xsolla.pm
1
package payments::Provider::Xsolla;
2
3
use strict;
4
use warnings 'all';
5
6
use base 'payments::Provider::Base';
7
use Contenido::Globals;
8
use payments::Keeper;
9
use Digest::MD5;
10
use Data::Dumper;
11
12
13
sub get_iframe {
14
my $self = shift;
15
my (%opts) = @_;
16
my $id = delete $opts{id};
17
return unless $id;
18
my $sum = delete $opts{sum};
19
return unless $sum;
20
21
$sum = $sum =~ /\d+\.\d{2}/ ? $sum : sprintf( "%.2f", $sum );
22
my @params = (
23
'marketplace=paydesk',
24
'theme=115',
25
'project='.$state->{payments}{xsolla_app_id},
26
'local=ru',
27
'pid=26',
28
'v1='.$id,
29
);
30
my $iframe = '<iframe id="paystation" src="https://secure.xsolla.com/paystation2/?'.join('&',@params).'" width="100%" height="100%">';
31
return $iframe;
32
}
33
34
35
1;
utf8/plugins/payments/lib/payments/SQL/OperationsTable.pm
1
package payments::SQL::OperationsTable;
2
3
use base 'SQL::DocumentTable';
4
5
sub db_table
6
{
7
return 'payments_operations';
8
}
9
10
11
sub available_filters {
12
my @available_filters = qw(
13
14
_class_filter
15
_status_filter
16
_in_id_filter
17
_id_filter
18
_name_filter
19
_class_excludes_filter
20
_sfilter_filter
21
_excludes_filter
22
_datetime_filter
23
_date_equal_filter
24
_date_filter
25
_previous_days_filter
26
27
_order_id_filter
28
_uid_filter
29
);
30
31
return \@available_filters;
32
}
33
34
# ----------------------------------------------------------------------------
35
# Свойства храним в массивах, потому что порядок важен!
36
# Это общие свойства - одинаковые для всех документов.
37
#
38
# attr - обязательный параметр, название атрибута;
39
# type - тип аттрибута, требуется для отображдения;
40
# rusname - русское название, опять же требуется для отображения;
41
# hidden - равен 1, когда
42
# readonly - инициализации при записи только без изменения в дальнейшем
43
# db_field - поле в таблице
44
# default - значение по умолчанию (поле всегда имеет это значение)
45
# ----------------------------------------------------------------------------
46
sub required_properties
47
{
48
my $self = shift;
49
50
my @parent_properties = grep { $_->{attr} ne 'dtime' && $_->{attr} ne 'sections' } $self->SUPER::required_properties;
51
return (
52
@parent_properties,
53
{
54
'attr' => 'uid',
55
'type' => 'integer',
56
'rusname' => 'ID пользователя',
57
'db_field' => 'uid',
58
'db_type' => 'integer',
59
'db_opts' => "default 0",
60
},
61
{ # ID заказа
62
'attr' => 'order_id',
63
'type' => 'integer',
64
'rusname' => 'ID заказа',
65
'db_field' => 'order_id',
66
'db_type' => 'integer',
67
'db_opts' => "not null",
68
},
69
{
70
'attr' => 'sum',
71
'type' => 'string',
72
'rusname' => 'Сумма',
73
'db_field' => 'sum',
74
'db_type' => 'float',
75
},
76
);
77
}
78
79
80
########### FILTERS DESCRIPTION ###############################################################################
81
sub _uid_filter {
82
my ($self,%opts)=@_;
83
return undef unless ( exists $opts{uid} );
84
return &SQL::Common::_generic_int_filter('d.uid', $opts{uid});
85
}
86
87
sub _order_id_filter {
88
my ($self,%opts)=@_;
89
return undef unless ( exists $opts{order_id} );
90
return &SQL::Common::_generic_int_filter('d.order_id', $opts{order_id});
91
}
92
93
1;
utf8/plugins/payments/lib/payments/SQL/TransactionsTable.pm
1
package payments::SQL::TransactionsTable;
2
3
use base 'SQL::DocumentTable';
4
5
sub db_table
6
{
7
return 'payments_transactions';
8
}
9
10
11
sub available_filters {
12
my @available_filters = qw(
13
14
_class_filter
15
_status_filter
16
_in_id_filter
17
_id_filter
18
_name_filter
19
_class_excludes_filter
20
_sfilter_filter
21
_excludes_filter
22
_datetime_filter
23
_date_equal_filter
24
_date_filter
25
_previous_days_filter
26
27
_operation_id_filter
28
_order_id_filter
29
_provider_filter
30
);
31
32
return \@available_filters;
33
}
34
35
# ----------------------------------------------------------------------------
36
# Свойства храним в массивах, потому что порядок важен!
37
# Это общие свойства - одинаковые для всех документов.
38
#
39
# attr - обязательный параметр, название атрибута;
40
# type - тип аттрибута, требуется для отображдения;
41
# rusname - русское название, опять же требуется для отображения;
42
# hidden - равен 1, когда
43
# readonly - инициализации при записи только без изменения в дальнейшем
44
# db_field - поле в таблице
45
# default - значение по умолчанию (поле всегда имеет это значение)
46
# ----------------------------------------------------------------------------
47
sub required_properties
48
{
49
my $self = shift;
50
51
my @parent_properties = grep { $_->{attr} ne 'sections' } $self->SUPER::required_properties;
52
return (
53
@parent_properties,
54
{
55
'attr' => 'provider',
56
'type' => 'string',
57
'rusname' => 'Провайдер',
58
'db_field' => 'provider',
59
'db_type' => 'text',
60
},
61
{
62
'attr' => 'account_id',
63
'type' => 'integer',
64
'rusname' => 'Аккаунт',
65
'db_field' => 'account_id',
66
'db_type' => 'numeric',
67
'db_opts' => "default 0",
68
},
69
{ # ID заказа
70
'attr' => 'order_id',
71
'type' => 'integer',
72
'rusname' => 'ID заказа',
73
'db_field' => 'order_id',
74
'db_type' => 'integer',
75
'db_opts' => "not null",
76
},
77
{ # ID заказа
78
'attr' => 'operation_id',
79
'type' => 'integer',
80
'rusname' => 'ID транзакции',
81
'db_field' => 'operation_id',
82
'db_type' => 'numeric',
83
'db_opts' => "not null",
84
},
85
{
86
'attr' => 'currency_code',
87
'type' => 'string',
88
'rusname' => 'ID валюты',
89
'db_field' => 'currency_code',
90
'db_type' => 'varchar(4)',
91
},
92
{
93
'attr' => 'sum',
94
'type' => 'string',
95
'rusname' => 'Сумма платежа',
96
'db_field' => 'sum',
97
'db_type' => 'float',
98
},
99
{
100
'attr' => 'account_user',
101
'type' => 'string',
102
'rusname' => 'Номер счета пользователя',
103
'db_field' => 'account_user',
104
'db_type' => 'text',
105
},
106
{
107
'attr' => 'account_corr',
108
'type' => 'string',
109
'rusname' => 'Номер счета плательщика',
110
'db_field' => 'account_corr',
111
'db_type' => 'text',
112
},
113
{
114
'attr' => 'payment_system',
115
'type' => 'string',
116
'rusname' => 'Идентификатор платежной системы',
117
'db_field' => 'payment_system',
118
'db_type' => 'text',
119
},
120
);
121
}
122
123
124
########### FILTERS DESCRIPTION ###############################################################################
125
sub _operation_id_filter {
126
my ($self,%opts)=@_;
127
return undef unless ( exists $opts{operation_id} );
128
return &SQL::Common::_generic_int_filter('d.operation_id', $opts{operation_id});
129
}
130
131
sub _order_id_filter {
132
my ($self,%opts)=@_;
133
return undef unless ( exists $opts{order_id} );
134
return &SQL::Common::_generic_int_filter('d.order_id', $opts{order_id});
135
}
136
137
sub _provider_filter {
138
my ($self,%opts)=@_;
139
return undef unless ( exists $opts{provider} );
140
return &SQL::Common::_generic_text_filter('d.provider', $opts{provider});
141
}
142
143
1;
utf8/plugins/payments/lib/payments/State.pm.proto
1
package payments::State;
2
3
use strict;
4
use warnings 'all';
5
use vars qw($AUTOLOAD);
6
7
8
sub new {
9
my ($proto) = @_;
10
my $class = ref($proto) || $proto;
11
my $self = {};
12
bless $self, $class;
13
14
# configured
15
$self->{debug} = (lc('') eq 'yes');
16
$self->{project} = '';
17
18
# зашитая конфигурация плагина
19
$self->{db_type} = 'none'; ### For REAL database use 'remote'
20
$self->{db_keepalive} = 0;
21
$self->{db_host} = '';
22
$self->{db_name} = '';
23
$self->{db_user} = '';
24
$self->{db_password} = '';
25
$self->{db_port} = '';
26
$self->{store_method} = 'toast';
27
$self->{cascade} = 1;
28
$self->{db_prepare} = 0;
29
30
$self->{memcached_enable} = lc( '' ) eq 'yes' ? 1 : 0;
31
$self->{memcached_enable_compress} = 1;
32
$self->{memcached_backend} = '';
33
$self->{memcached_servers} = [qw()];
34
$self->{memcached_busy_lock} = 60;
35
$self->{memcached_delayed} = lc('') eq 'yes' ? 1 : 0;
36
37
$self->{serialize_with} = 'json'; ### or 'dumper'
38
39
# not implemented really (core compatibility)
40
$self->{binary_directory} = '/nonexistent';
41
$self->{data_directory} = '/nonexistent';
42
$self->{images_directory} = '/nonexistent';
43
$self->{preview} = '0';
44
45
$self->{moneta_app_id} = '@MNT_ID@';
46
$self->{moneta_app_secret} = '@MNT_SECRET@';
47
$self->{moneta_currency_code} = '@MNT_CURRENCY_CODE@';
48
$self->{moneta_test_mode} = int('@MNT_TEST_MODE@' || 0);
49
$self->{moneta_sig_code} = '@MNT_SIG_CODE@';
50
51
$self->{xsolla_app_id} = '@XSO_ID@';
52
$self->{xsolla_app_secret} = '@XSO_SECRET@';
53
$self->{xsolla_currency_code} = '@XSO_CURRENCY_CODE@';
54
$self->{xsolla_test_mode} = int('@XSO_TEST_MODE@' || 0);
55
56
$self->_init_();
57
$self;
58
}
59
60
sub info {
61
my $self = shift;
62
return unless ref $self;
63
64
for (sort keys %{$self->{attributes}}) {
65
my $la = length $_;
66
warn "\t$_".("\t" x (2-int($la/8))).": $self->{$_}\n";
67
}
68
}
69
70
sub _init_ {
71
my $self = shift;
72
73
# зашитая конфигурация плагина
74
$self->{attributes}->{$_} = 'SCALAR' for qw(
75
debug
76
project
77
78
db_type
79
db_keepalive
80
db_host
81
db_port
82
db_name
83
db_user
84
db_password
85
store_method
86
cascade
87
db_prepare
88
db_client_encoding
89
90
memcached_enable
91
memcached_enable_compress
92
memcached_backend
93
memcached_servers
94
memcached_busy_lock
95
memcached_delayed
96
97
binary_directory
98
data_directory
99
images_directory
100
preview
101
);
102
}
103
104
sub AUTOLOAD {
105
my $self = shift;
106
my $attribute = $AUTOLOAD;
107
108
$attribute =~ s/.*:://;
109
return unless $attribute =~ /[^A-Z]/; # Отключаем методы типа DESTROY
110
111
if (!exists $self->{attributes}->{$attribute}) {
112
warn "Contenido Error (payments::State): Вызов метода, для которого не существует обрабатываемого свойства: ->$attribute()\n";
113
return;
114
}
115
116
$self->{$attribute} = shift @_ if $#_>=0;
117
$self->{$attribute};
118
}
119
120
1;
utf8/plugins/payments/lib/payments/Transaction.pm
1
package payments::Transaction;
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
{ 'attr' => 'custom1', 'type' => 'string', 'rusname' => 'Параметр 1' },
14
{ 'attr' => 'custom2', 'type' => 'string', 'rusname' => 'Параметр 2' },
15
{ 'attr' => 'custom3', 'type' => 'string', 'rusname' => 'Параметр 3' },
16
)
17
}
18
19
sub class_name
20
{
21
return 'Payments: транзакция';
22
}
23
24
sub class_description
25
{
26
return 'Payments: транзакция';
27
}
28
29
sub class_table
30
{
31
return 'payments::SQL::TransactionsTable';
32
}
33
34
1;
utf8/plugins/payments/lib/payments/TransactionSection.pm
1
package payments::TransactionSection;
2
3
use base 'Contenido::Section';
4
5
sub extra_properties
6
{
7
return (
8
{ 'attr' => 'brief', 'type' => 'text', 'rusname' => 'Описание секции' },
9
{ 'attr' => 'default_document_class', 'default' => 'payments::Transaction' },
10
{ 'attr' => '_sorted', 'hidden' => 1 },
11
{ 'attr' => 'order_by', 'hidden' => 1 },
12
)
13
}
14
15
sub class_name
16
{
17
return 'Payments: Секция транзакций';
18
}
19
20
sub class_description
21
{
22
return 'Payments: Секция транзакций';
23
}
24
25
1;
utf8/plugins/payments/sql/TOAST/operations.sql
1
create table payments_operations
2
(
3
id integer not null primary key default nextval('public.documents_id_seq'::text),
4
class text not null,
5
ctime timestamp not null default now(),
6
mtime timestamp not null default now(),
7
status smallint not null default 0,
8
name text,
9
order_id integer not null,
10
uid integer not null,
11
sum float,
12
data text
13
);
14
CREATE INDEX payments_operations_order ON payments_operations USING btree (order_id);
utf8/plugins/payments/sql/TOAST/transactions.sql
1
create table payments_transactions
2
(
3
id integer not null primary key default nextval('public.documents_id_seq'::text),
4
class text not null,
5
ctime timestamp not null default now(),
6
mtime timestamp not null default now(),
7
dtime timestamp not null default now(),
8
status smallint not null default 0,
9
provider text,
10
name text,
11
account_id numeric,
12
order_id integer not null,
13
operation_id numeric not null,
14
currency_code varchar(4),
15
sum float,
16
account_user text,
17
payment_system text,
18
account_corr text,
19
data text
20
);
21
CREATE INDEX payments_transactions_operations ON payments_transactions USING btree (provider, operation_id);
22
CREATE INDEX payments_transactions_orders ON payments_transactions USING btree (order_id);
Небольшая справка по веткам
cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.
koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.
utf8 – актуальная ветка, заточенная под UTF-8.
Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.