Revision 429
Date:
2014/03/14 20:03:40
Author:
ahitrov
Revision Log:
Discount can be counted for item groups and individual items
Discount can be based on additional price fields
Files:
Legend:
Added
Removed
Modified
utf8/plugins/webshop/lib/webshop/Discount.pm
32
32
rem => 'Список разделов, на содержимое которых распространяется скидка по купону',
33
33
},
34
34
{ 'attr' => 'min_sum', 'type' => 'string', 'rusname' => 'Порог суммы, с которого действует скидка',
35
default => 0, column => 2, shortname => 'Сумма заказа' },
35
default => 0, column => 6, shortname => 'Сумма заказа' },
36
{ 'attr' => 'field', 'type' => 'string', 'rusname' => 'Название ценовой колонки', shortname => 'Колонка',
37
column => 7,
38
rem => 'Используется название, отмеченное серым цветом в "name=priceNN"' },
36
39
{ 'attr' => 'discount', 'type' => 'string', 'rusname' => 'Размер скидки (число или процент)', shortname => 'Скидка',
37
default => 0, column => 3 },
40
default => 0, column => 8,
41
rem => 'Данное поле будет задействовано, если не указана ценовая колонка', },
38
42
)
39
43
}
40
44
…
…
78
82
my $self = shift;
79
83
80
84
my (%opts) = @_;
81
my $basket = delete $opts{basket};
82
return 0 unless exists $opts{uid} && $opts{uid} || exists $opts{session} && $opts{session};
85
return 0 unless exists $opts{basket} || exists $opts{uid} && $opts{uid} || exists $opts{session} && $opts{session};
83
86
return 0 unless $self->discount;
84
87
85
$basket ||= $keeper->{webshop}->get_basket ( %opts );
88
my $basket = delete $opts{basket};
89
$basket = $keeper->{webshop}->get_basket ( %opts ) unless $basket;
86
90
return 0 unless ref $basket eq 'ARRAY' && @$basket;
87
91
92
my @basket = grep { exists $_->{item} && $_->{item} } @$basket;
93
return 0 unless @basket;
94
88
95
my ($number, $sum_total) = (0, 0);
89
map { $number += $_->number; $sum_total += $_->number * $_->price } @$basket;
96
map { $number += $_->number; $sum_total += $_->number * $_->{item}->price } @basket;
90
97
warn "BASKET: $number Items of $sum_total Value\n";
91
98
99
my %item_props = map { $_->{attr} => $_ } $basket[0]->{item}->structure;
100
if ( exists $item_props{special_price} ) {
101
@basket = grep { !$_->{item}->special_price } @basket;
102
return 0 unless @basket;
103
}
104
92
105
my $discount_counted = 0;
93
106
my $items;
94
107
if ( $self->groups ) {
95
108
$items = $self->keeper->get_documents (
96
109
s => [$self->groups],
97
110
class => $state->{webshop}->{item_document_class},
98
light => 1,
111
ids => 1,
99
112
return_mode => 'array_ref',
100
113
);
114
return 0 unless ref $items eq 'ARRAY' && @$items;
101
115
} else {
102
116
$items = $self->keeper->get_documents (
103
117
class => $state->{webshop}->{item_document_class},
104
118
lclass => 'webshop::DiscountItemLink',
105
119
lsource => $self->id,
106
light => 1,
120
ids => 1,
107
121
return_mode => 'array_ref',
108
122
);
109
123
}
110
124
111
125
if ( ref $items eq 'ARRAY' && @$items ) {
112
my $found_sum = 0;
113
foreach my $bi ( @$basket ) {
114
warn "BASKET: Item id [".$bi->item_id."]\n" if $DEBUG;
115
next if $bi->special_price;
116
foreach my $item ( @$items) {
117
if ( $bi->item_id == $item->id ) {
118
warn "BASKET: Item [".$item->name."] id [".$item->id."]\n" if $DEBUG;
119
$found_sum += $bi->number * $bi->price;
120
last;
121
}
122
}
126
my %items = map { $_ => 1 } @$items;
127
@basket = grep { exists $items{$_->item_id} } @basket;
128
return 0 unless @basket;
129
}
130
if ( $self->field ) {
131
foreach my $bi ( @basket ) {
132
next if exists $bi->{item}{special_price} && $bi->{item}->special_price;
133
$discount_counted += $self->count_item_discount( $bi->{item} ) * $bi->number;
123
134
}
124
warn "Sum found: [$found_sum]\n" if $DEBUG;
125
return $self->can_discount( $found_sum );
126
} elsif ( $self->groups ) {
127
return 0;
128
135
} else {
129
136
my $found_sum = 0;
130
137
foreach my $bi ( @$basket ) {
131
warn "BASKET: Item id [".$bi->item_id."]\n" if $DEBUG;
132
next if $bi->special_price;
133
$found_sum += $bi->number * $bi->price;
138
$found_sum += $bi->number * $bi->{item}->price;
134
139
}
135
140
warn "Sum found: [$found_sum]\n" if $DEBUG;
136
return $self->can_discount( $found_sum );
141
$discount_counted = $self->count_sum_discount( $found_sum );
137
142
}
138
return 0;
143
return $discount_counted;
139
144
}
140
145
141
146
142
sub can_discount
147
sub count_item_discount {
148
my $self = shift;
149
my $item = shift;
150
return 0 unless $item;
151
return 0 if exists $item->{special_price} && $item->special_price;
152
153
my $count = 0;
154
my $item_field = $self->field;
155
$item_field =~ s/\s//sg;
156
if ( $item_field && $item->$item_field && $item->price > $item->$item_field ) {
157
$count = $item->price - $item->$item_field;
158
} elsif ( $self->discount ) {
159
my $value = $self->discount;
160
$value =~ s/\s//sg;
161
if ( $value =~ /([\d\.]+)%/ ) {
162
my $proc = $1;
163
$count = $item->price / 100 * $proc;
164
}
165
}
166
return $count;
167
}
168
169
sub count_sum_discount
143
170
{
144
171
my $self = shift;
145
172
my $sum = shift;
146
173
return 0 unless $sum;
147
174
148
175
my $discount = $self->discount;
149
my $min_sum = $self->min_sum || 0;
150
176
my $count = 0;
151
177
if ( $discount =~ /([\d\.]+)%/ ) {
152
178
my $proc = $1;
…
…
155
181
} else {
156
182
$count = $discount;
157
183
}
158
my $rest = $sum - $count;
159
$count = 0 if $rest < $min_sum || $rest == 0;
184
$count = 0 if $sum <= $count;
160
185
return $count;
161
186
}
162
187
utf8/plugins/webshop/lib/webshop/Keeper.pm
153
153
154
154
return unless $opts{uid} || $opts{session} || $opts{order_id};
155
155
156
my $with_products = delete $opts{with_products} || 0;
156
157
my $uid = delete $opts{uid};
157
158
my $session_id = delete $opts{session};
158
159
unless ( exists $opts{order_id} && $opts{order_id} ) {
…
…
164
165
}
165
166
}
166
167
$opts{status} = 1 unless exists $opts{status} && defined $opts{status};
167
my @items = $keeper->get_documents (
168
my @basket = $keeper->get_documents (
168
169
class => 'webshop::Basket',
169
170
%opts,
170
171
);
171
172
my $total = 0;
172
173
my $sum = 0;
173
foreach my $item ( @items ) {
174
if ( $item->status == 1 ) {
175
$total += $item->number;
176
$sum += $item->number * $item->price;
174
my $items;
175
if ( $with_products ) {
176
my %ids = map { $_->item_id => 1 } @basket;
177
my @ids = keys %ids;
178
$items = @ids ? $keeper->get_documents (
179
id => \@ids,
180
class => $state->{webshop}->{item_document_class},
181
return_mode => 'hash_ref',
182
) : {};
183
}
184
foreach my $bi ( @basket ) {
185
if ( $bi->status == 1 ) {
186
$total += $bi->number;
187
$sum += $bi->number * ($bi->price || 0);
177
188
}
189
if ( ref $items eq 'HASH' && exists $items->{$bi->item_id} ) {
190
$bi->{item} = $items->{$bi->item_id};
191
}
178
192
}
179
return \@items;
193
return \@basket;
180
194
}
181
195
182
196
…
…
418
432
} else {
419
433
$dopts{uid} = 0;
420
434
}
421
my $basket = exists $opts{basket} ? $opts{basket} : $self->get_basket( %opts );
435
my $basket = exists $opts{basket} ? $opts{basket} : $self->get_basket( %opts, with_products => 1 );
436
return 0 unless ref $basket eq 'ARRAY' && @$basket;
437
my @basket = grep { exists $_->{item} && $_->{item} } @$basket;
438
return 0 unless @basket;
422
439
423
440
my $now = Contenido::DateTime->new;
424
441
my @discounts = $keeper->get_documents(
…
…
429
446
);
430
447
return 0 unless @discounts;
431
448
my @summoned = sort { $b->min_sum <=> $a->min_sum } grep { $_->min_sum && $_->discount && $_->min_sum =~ /^\d+$/ } @discounts;
432
my ($total, $sum) = $self->basket_count( $basket );
449
my ($total, $sum) = $self->basket_count( \@basket );
433
450
return 0 unless $sum;
434
451
my $result = 0;
435
452
foreach my $discount ( @summoned ) {
436
453
if ( $sum > $discount->min_sum ) {
437
my $res = 0;
438
my $value = $discount->discount;
439
$value =~ s/\s//sg;
440
if ( $value =~ /([\d\.]+)%/ ) {
441
my $proc = $1;
442
$res = $sum / 100 * $proc;
443
} elsif ( $value =~ /([\d\.]+)/ ) {
444
my $res = $1;
445
}
454
my $res = $discount->get_discount( basket => \@basket );
446
455
$result = $res if $res > $result;
447
456
}
448
457
}
Небольшая справка по веткам
cnddist – контейнер, в котором хранятся все дистрибутивы всех библиотек и программных пакетов, которые использовались при построении различных версий Contenido. Если какой-то библиотеки в данном хранилище нет, инсталлятор сделает попытку "подтянуть" ее с веба (например, с CPAN). Если библиотека слишком старая, есть очень большая вероятность, что ее там уже нет. Поэтому мы храним весь хлам от всех сборок. Если какой-то дистрибутив вдруг отсутствует в cnddist - напишите нам, мы положим его туда.
koi8 – отмирающая ветка, чей код, выдача и все внутренние библиотеки заточены на кодировку KOI8-R. Вносятся только те дополнения, которые касаются внешнего вида и функционала админки, баги ядра, обязательные обновления портов и мелочи, которые легко скопипастить. В дальнейшем планируется полная остановка поддержки по данной ветке.
utf8 – актуальная ветка, заточенная под UTF-8.
Внутри каждой ветки: core – исходники ядра; install – скрипт установки инсталляции; plugins – плагины; samples – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.