mirror of
https://github.com/FOSSBilling/FOSSBilling.git
synced 2026-11-10 14:03:30 +09:00
Correctly use qantity for invoice items prices
This commit is contained in:
1 parent
b94d9741fa
commit
ce3e02eca5
7 files changed
+77
-37
No files matched your search
@@ -124,6 +124,6 @@ class Payment_Invoice_Item
|
||||
|
||||
public function getTotalWithTax()
|
||||
{
|
||||
return $this->getTotal() + $this->getQuantity() * $this->getTax();
|
||||
return $this->getTotal() + $this->getTax();
|
||||
}
|
||||
}
|
||||
@@ -323,8 +323,8 @@ class Service implements InjectionAwareInterface
|
||||
$items_discount = 0;
|
||||
foreach ($products as $product) {
|
||||
$p = $this->cartProductToApiArray($product);
|
||||
$total += $p['total'];
|
||||
$items_discount += $p['discount_price'];
|
||||
$total += $p['total'] + $p['setup_price'];
|
||||
$items_discount += $p['discount'];
|
||||
$items[] = $p;
|
||||
}
|
||||
|
||||
@@ -546,7 +546,7 @@ class Service implements InjectionAwareInterface
|
||||
|
||||
$invoice_items[] = array(
|
||||
'title' => $order->title,
|
||||
'price' => $order->price * $order->quantity,
|
||||
'price' => $order->price,
|
||||
'quantity' => $order->quantity,
|
||||
'unit' => $order->unit,
|
||||
'period' => $order->period,
|
||||
@@ -563,6 +563,7 @@ class Service implements InjectionAwareInterface
|
||||
'quantity' => 1,
|
||||
'unit' => 'discount',
|
||||
'rel_id' => $order->id,
|
||||
'taxed' => $taxed,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -731,6 +732,14 @@ class Service implements InjectionAwareInterface
|
||||
|
||||
list ($discount_price, $discount_setup) = $this->getProductDiscount($model, $setup);
|
||||
|
||||
$discount_total = $discount_price + $discount_setup;
|
||||
|
||||
$subtotal = ($price * $qty);
|
||||
if(abs($discount_total) > ($subtotal + $setup) ) {
|
||||
$discount_total = $subtotal;
|
||||
$discount_price = $subtotal;
|
||||
}
|
||||
|
||||
$data = array_merge($config, array(
|
||||
'id' => $model->id,
|
||||
'product_id' => $product->id,
|
||||
@@ -741,9 +750,10 @@ class Service implements InjectionAwareInterface
|
||||
'unit' => $repo->getUnit($product),
|
||||
'price' => $price,
|
||||
'setup_price' => $setup,
|
||||
'discount' => $discount_total,
|
||||
'discount_price'=> $discount_price,
|
||||
'discount_setup'=> $discount_setup,
|
||||
'total' => ($price * $qty) ,
|
||||
'total' => $subtotal,
|
||||
));
|
||||
return $data;
|
||||
}
|
||||
|
||||
@@ -146,16 +146,8 @@ class Service implements InjectionAwareInterface
|
||||
foreach($items as $item) {
|
||||
$order_id = ($item->type == \Model_InvoiceItem::TYPE_ORDER) ? $item->rel_id : null;
|
||||
|
||||
/* Item quantity shouldn't be used to determine total price at this point.
|
||||
* The total price must be determined when invoice is being generated else recurring discounts will be
|
||||
* applied by a factor of the quantity instead of being applied once as demonstrated below.
|
||||
* If the order has a recurring discount, the price that is fetched already has the discount applied. Example:
|
||||
* Case 1 - correct: $item->price = ($order->price * $order->quantity) - $order->discount
|
||||
* Case 2 - incorrect: $item->price = ($order->price - $order->discount) * $order->quantity
|
||||
* However, case 1 cannot be calculated at this point because invoice_item doesn't store discount so the calculation must
|
||||
* be done before calling toApiArray.
|
||||
*/
|
||||
$total += $item->price;
|
||||
$line_total = $item->price * $item->quantity;
|
||||
$total += $line_total;
|
||||
$line_tax = $invoiceItemService->getTax($item) * $item->quantity;
|
||||
$tax_total += $line_tax;
|
||||
$line = array(
|
||||
@@ -168,7 +160,7 @@ class Service implements InjectionAwareInterface
|
||||
'tax' => $line_tax,
|
||||
'taxed' => $item->taxed,
|
||||
'charged' => $item->charged,
|
||||
'total' => $item->price, //total appears to be redundant.
|
||||
'total' => $line_total,
|
||||
'order_id' => $order_id,
|
||||
'type' => $item->type,
|
||||
'rel_id' => $item->rel_id,
|
||||
@@ -945,16 +937,7 @@ class Service implements InjectionAwareInterface
|
||||
|
||||
$this->setInvoiceDefaults($proforma);
|
||||
|
||||
$price = $order->price * $order->quantity;
|
||||
// apply discount for new invoice if promo code is recurrent
|
||||
if($order->promo_recurring) {
|
||||
$price = $price - $order->discount;
|
||||
if($price < 0) {
|
||||
$price = 0;
|
||||
}
|
||||
$order->promo_used +=1;
|
||||
$this->di['db']->store($order);
|
||||
}
|
||||
$price = $order->price;
|
||||
|
||||
$invoiceItemService = $this->di['mod_service']('Invoice', "InvoiceItem");
|
||||
$invoiceItemService->generateFromOrder($proforma, $order, \Model_InvoiceItem::TASK_RENEW, $price);
|
||||
|
||||
@@ -312,6 +312,49 @@ class ServiceInvoiceItem implements InjectionAwareInterface
|
||||
$this->di['db']->store($pi);
|
||||
|
||||
$corderService->setUnpaidInvoice($order, $proforma);
|
||||
|
||||
// apply discount for new invoice if promo code is recurrent
|
||||
if($order->promo_recurring) {
|
||||
$order_total = $order->price * $order->quantity;
|
||||
$promo_discount = $order->discount;
|
||||
if($promo_discount > $order_total) {
|
||||
$promo_discount = $order_total;
|
||||
}
|
||||
|
||||
$discount_title = $this->_getTitleForPromoDiscount($order->promo_id, $order->currency);
|
||||
|
||||
$pd = [
|
||||
'title' => $discount_title,
|
||||
'price' => $promo_discount * -1,
|
||||
'quantity' => 1,
|
||||
'unit' => 'discount',
|
||||
'rel_id' => $order->id,
|
||||
'taxed' => $taxed,
|
||||
];
|
||||
|
||||
$this->addNew($proforma, $pd);
|
||||
$order->promo_used +=1;
|
||||
$this->di['db']->store($order);
|
||||
}
|
||||
}
|
||||
|
||||
private function _getTitleForPromoDiscount($promo_id, $currency)
|
||||
{
|
||||
$promo = $this->di['db']->findOne('Promo', 'id = ?', [$promo_id]);
|
||||
|
||||
$api_guest = $this->di['api_guest'];
|
||||
|
||||
switch ($promo->type) {
|
||||
case \Model_Promo::ABSOLUTE:
|
||||
$currencyAmount = $api_guest->currency_format(['code' => $currency, 'price' => $promo->value]);
|
||||
return __('Promotional Code: :code - :value Discount', [':code' => $promo->code, ':value' => $currencyAmount]);
|
||||
|
||||
case \Model_Promo::PERCENTAGE:
|
||||
return __('Promotional Code: :code - :value%', [':code' => $promo->code, ':value' => $promo->value]);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -962,6 +962,7 @@ class Service implements InjectionAwareInterface
|
||||
}
|
||||
|
||||
$discount = 0;
|
||||
$quantity = 1;
|
||||
|
||||
switch ($promo->type) {
|
||||
case \Model_Promo::ABSOLUTE:
|
||||
@@ -969,7 +970,12 @@ class Service implements InjectionAwareInterface
|
||||
break;
|
||||
|
||||
case \Model_Promo::PERCENTAGE:
|
||||
$discount += round(($price * $promo->value / 100), 2);
|
||||
|
||||
if(isset($config['quantity']) && is_numeric($config['quantity'])){
|
||||
$quantity = $config['quantity'];
|
||||
}
|
||||
|
||||
$discount += round(($price * $quantity * $promo->value / 100), 2);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1063,4 +1069,4 @@ class Service implements InjectionAwareInterface
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -548,6 +548,7 @@ class Service implements \Box\InjectionAwareInterface
|
||||
$data['replies'] = $this->messageGetRepliesCount($model);
|
||||
$data['first'] = $this->messageToApiArray($firstSupportTicketMessage);
|
||||
$data['helpdesk'] = $this->helpdeskToApiArray($supportHelpdesk);
|
||||
$data['client'] = $this->getClientApiArrayForTicket($model);
|
||||
|
||||
if ($deep) {
|
||||
$messages = $this->messageGetTicketMessages($model);
|
||||
@@ -559,7 +560,6 @@ class Service implements \Box\InjectionAwareInterface
|
||||
if ($identity instanceof \Model_Admin) {
|
||||
$data['rel'] = $this->_getRelDetails($model);
|
||||
$data['priority'] = $model->priority;
|
||||
$data['client'] = $this->getClientApiArrayForTicket($model);
|
||||
$supportTicketNotes = $this->di['db']->find('SupportTicketNote', 'support_ticket_id = :support_ticket_id', array(':support_ticket_id' => $model->id));
|
||||
|
||||
foreach ($supportTicketNotes as $note) {
|
||||
|
||||
@@ -42,10 +42,10 @@
|
||||
<td>{{ item.period | period_title }}</td>
|
||||
<td class="currency">
|
||||
{% if item.discount_price %}
|
||||
<del>{{ (item.price*item.quantity) | money_convert }}</del>
|
||||
{{ (item.price*item.quantity - item.discount_price*item.quantity) | money_convert }}
|
||||
<del>{{ (item.total) | money_convert }}</del>
|
||||
{{ (item.total - item.discount_price) | money_convert }}
|
||||
{% else %}
|
||||
{{ item.price | money_convert }}
|
||||
{{ (item.total) | money_convert }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
@@ -96,11 +96,9 @@
|
||||
<div class="currency">{{ tax_amount | money_convert }}</div>
|
||||
{% endif %}
|
||||
<p>{% trans 'Total:' %}</p>
|
||||
<div class="currency">{% if cart.items[1].quantity > 1 and cart.items[1].discount_price%}
|
||||
{{ (cart.total - (cart.items[1].price*(cart.items[1].quantity-1))) | money_convert }}
|
||||
{%else%}
|
||||
{{(cart.total + tax_amount) | money_convert }}
|
||||
{%endif%}</div>
|
||||
<div class="currency">
|
||||
{{(cart.total + tax_amount) | money_convert }}
|
||||
</div>
|
||||
<form method="post" action="{{ 'api/client/cart/checkout'|link }}" class="api-form" data-api-jsonp="onAfterCartCheckout">
|
||||
{% set enough_in_balance = client.client_balance_get_total >= cart.total %}
|
||||
{% if cart.total and not enough_in_balance %}
|
||||
|
||||
Reference in new issue
Block a user