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 – "готовые к употреблению" проекты, которые можно поставить, запустить и посмотреть, как они работают.