Revision 810
- Date:
- 2021/02/05 22:07:54
- Files:
Legend:
- Added
- Removed
- Modified
-
utf8/plugins/webshop/lib/webshop/Discount.pm
20 20 [1, 'Скидка активна'], 21 21 ], 22 22 }, 23 { 'attr' => 'mechanic', 'type' => 'status', 'rusname' => 'Механика', 24 'cases' => [ 25 ['simple', 'Простая скидка'], 26 ['two_as_one', 'Скидка на каждую вторую покупку'], 27 ], 28 }, 23 29 { 'attr' => 'uid', 'type' => 'status', 'rusname' => 'Доступность для пользователей', 24 30 'cases' => [ 25 31 [0, 'Скидка доступна всем пользователям'], … … 127 133 @basket = grep { exists $items{$_->item_id} } @basket; 128 134 return 0 unless @basket; 129 135 } 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; 134 } 136 if ( $self->mechanic eq 'two_as_one' ) { 137 $discount_counted = $self->mechanic_two_as_one( \@basket ); 135 138 } else { 136 my $found_sum = 0; 137 foreach my $bi ( @$basket ) { 138 $found_sum += $bi->number * $bi->{item}->price; 139 } 140 warn "Sum found: [$found_sum]\n" if $DEBUG; 141 $discount_counted = $self->count_sum_discount( $found_sum ); 139 $discount_counted = $self->mechanic_simple( \@basket ); 142 140 } 143 return $discount_counted; 141 142 return wantarray ? ($discount_counted, \@basket) : $discount_counted; 144 143 } 145 144 146 145 147 sub count_item_discount { 146 sub mechanic_simple { 148 147 my $self = shift; 149 my $item = shift; 150 return 0 unless $item; 151 return 0 if exists $item->{special_price} && $item->special_price; 148 my $basket = shift; 149 return 0 unless ref $basket eq 'ARRAY' && @$basket; 152 150 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; 151 my $discount = 0; 152 my $price_field = $self->field; 153 $price_field =~ s/\s//sg; 154 $price_field ||= 'price'; 155 my $value = $self->discount; 156 $value =~ s/\s//sg; 157 return 0 unless $value; 158 my ($proc, $fixed); 159 if ( $value =~ /([\d\.]+)\s*%/ ) { 160 $proc = $1; 161 } elsif ( $value =~ /^\s*([\d\.]+)\s*$/ ) { 162 $fixed = $1; 163 } else { 164 return 0; 165 } 166 167 foreach my $bi ( @$basket ) { 168 my $item_discount = 0; 169 if ( $proc ) { 170 $item_discount += $bi->{item}->$price_field / 100 * $proc; 171 } else { 172 $item_discount += $bi->{item}->$price_field > $fixed ? $fixed : 0; 164 173 } 174 my $sum = ($bi->{item}->$price_field - $item_discount) * $bi->number; 175 $bi->{sum_discounted}{$self->id}{sum_show} = $sum; 176 $bi->{sum_discounted}{$self->id}{sum_bill} = $sum; 177 $bi->{sum_discounted}{$self->id}{discount} = $item_discount * $bi->number; 178 $discount += $bi->{sum_discounted}{$self->id}{discount}; 165 179 } 166 return $count; 180 181 return $discount; 167 182 } 168 183 184 sub mechanic_two_as_one { 185 my $self = shift; 186 my $basket = shift; 187 return 0 unless ref $basket eq 'ARRAY'; 188 189 my @new_basket; 190 foreach my $bi ( @$basket ) { 191 $bi->{sum_discounted} = {}; 192 for ( my $i = 0; $i < $bi->number; $i++ ) { 193 push @new_basket, $bi; 194 } 195 } 196 return 0 if scalar @new_basket <= 1; 197 198 my $price_field = $self->field; 199 $price_field =~ s/\s//sg; 200 $price_field ||= 'price'; 201 202 my $value = $self->discount; 203 $value =~ s/\s//sg; 204 $value ||= '100%'; 205 my ($proc, $fixed); 206 if ( $value =~ /([\d\.]+)\s*%/ ) { 207 $proc = $1; 208 } elsif ( $value =~ /^\s*([\d\.]+)\s*$/ ) { 209 $fixed = $1; 210 } else { 211 return 0; 212 } 213 214 my $discount = 0; 215 my @sorted = sort { $b->{item}->$price_field <=> $a->{item}->$price_field } @new_basket; 216 my $border = int(scalar(@sorted) / 2) + scalar(@sorted) % 2; 217 218 my $sum = 0; 219 for( my $i = 0; $i < scalar(@sorted); $i++ ) { 220 my $bi = $sorted[$i]; 221 $sum += $bi->{item}->$price_field; 222 if ( $i >= $border ) { 223 my $item_discount = 0; 224 if ( $proc ) { 225 $item_discount = $bi->{item}->$price_field * ($proc / 100); 226 } else { 227 $item_discount = $bi->{item}->$price_field > $fixed ? $fixed : 0; 228 } 229 $bi->{sum_discounted}{$self->id}{sum_show} += $bi->{item}->$price_field - $item_discount; 230 $bi->{sum_discounted}{$self->id}{discount} += $item_discount; 231 $discount += $item_discount; 232 } else { 233 $bi->{sum_discounted}{$self->id}{sum_show} += $bi->{item}->$price_field; 234 } 235 } 236 my $avg_discount = ($sum - $discount) / $sum; 237 foreach my $bi ( @sorted ) { 238 my $bill_price = $bi->{item}->$price_field * $avg_discount; 239 $bi->{sum_discounted}{$self->id}{sum_bill} += $bill_price; 240 } 241 242 return $discount; 243 } 244 169 245 sub count_sum_discount 170 246 { 171 247 my $self = shift; … … 197 273 } 198 274 199 275 if ( $self->discount ) { 200 $self->{discount} =~ s/\D//sg; 276 $self->{discount} =~ s/[^\d\.%]//sg; 201 277 } 202 278 203 279 return 1; -
utf8/plugins/webshop/lib/webshop/Keeper.pm
508 508 } 509 509 } 510 510 511 my ($discount_sum, $discount_payment) = (0, 0); 512 511 513 my $now = Contenido::DateTime->new; 512 514 my @discounts = $keeper->get_documents( 513 515 class => 'webshop::Discount', … … 515 517 interval=> [$now, $now], 516 518 %dopts, 517 519 ); 518 my @summoned = sort { $b->min_sum <=> $a->min_sum } grep { $_->min_sum && $_->discount && $_->min_sum =~ /^\d+$/ } @discounts; 520 my @summoned = sort { $b->min_sum <=> $a->min_sum } grep { $_->discount && $_->min_sum =~ /^\d+$/ } @discounts; 521 warn "Summoned: ".scalar(@summoned)." discounts\n" if $DEBUG; 519 522 my ($total, $sum) = $self->basket_count( \@basket ); 523 warn "Sum: $sum\n" if $DEBUG; 520 524 return 0 unless $sum; 521 my $result = 0; 525 526 my $discount_used; 522 527 foreach my $discount ( @summoned ) { 528 warn "Check discount: ".$discount->name."\n" if $DEBUG; 523 529 if ( $sum > $discount->min_sum ) { 524 530 my $res = $discount->get_discount( basket => \@basket ); 525 $result = $res if $res > $result; 531 warn "Discount result: $res\n" if $DEBUG; 532 if ( $res > $discount_sum && $res < $sum ) { 533 $discount_sum = $res; 534 $discount_used = $discount; 535 } 526 536 } 527 537 } 538 if ( ref $discount_used ) { 539 foreach my $bi ( @basket ) { 540 if ( exists $bi->{sum_discounted} && exists $bi->{sum_discounted}{$discount_used->id} ) { 541 $bi->{sum_discounted} = $bi->{sum_discounted}{$discount_used->id}; 542 } else { 543 $bi->{sum_discounted} = {}; 544 } 545 } 546 } 528 547 529 548 my $summarize = 0; 530 549 if ( ref $payment && $payment->discount && $payment->discount > 0 ) { … … 541 560 } 542 561 if ( $payment->summarize ) { 543 562 $summarize = 1; 544 $result += $payment_discount_sum if $payment_discount_sum + $result < $sum; 545 } else { 546 $result = $payment_discount_sum if $payment_discount_sum > $result; 547 563 } 564 $discount_payment = $payment_discount_sum if $payment_discount_sum < $sum; 548 565 } 549 566 550 $result = 0 if $result >= $sum; 551 return ($result, $summarize); 567 return ($discount_sum, $discount_payment, $summarize); 552 568 } 553 569 554 555 570 sub check_coupons { 556 571 my $self = shift; 557 572 my (%opts) = @_;