diff --git a/app/Listeners/ExpensesEventSubscriber.php b/app/Listeners/ExpensesEventSubscriber.php index 6f58ed65f..83a561cdf 100755 --- a/app/Listeners/ExpensesEventSubscriber.php +++ b/app/Listeners/ExpensesEventSubscriber.php @@ -137,7 +137,7 @@ function( ExpenseAfterUpdateEvent $event ) { $event->listen( OrderAfterProductRefundedEvent::class, function( OrderAfterProductRefundedEvent $event ) { - $this->expenseService->createExpenseFromRefund( $event->orderProductRefund, $event->orderProduct ); + $this->expenseService->createExpenseFromRefund( $event->order, $event->orderProductRefund, $event->orderProduct ); } ); } diff --git a/app/Models/Order.php b/app/Models/Order.php index f83d9a8b8..30495f921 100755 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -159,54 +159,49 @@ public function scopePaymentStatusIn( $query, array $statuses ) * or all the product if it's enabled or disabled. * @return array */ - public function getProductsAttribute() + public function getCombinedProductsAttribute() { if ( ns()->option->get( 'ns_invoice_merge_similar_products', 'no' ) === 'yes' ) { - return $this->combinedProducts; + $combinaison = []; + + $this->products()->with( 'unit' )->get()->each( function( $product ) use ( &$combinaison ){ + $values = $product->toArray(); + + extract( $values ); + + $keys = array_keys( $combinaison ); + $stringified = Hook::filter( 'ns-products-combinaison-identifier', $product_id . '-' . $order_id . '-' . $discount . '-' . $product_category_id . '-' . $status, $product ); + $combinaisonAttributes = Hook::filter( 'ns-products-combinaison-attributes', [ + 'quantity', + 'total_gross_price', + 'total_price', + 'total_purchase_price', + 'total_net_price', + 'discount' + ]); + + if ( in_array( $stringified, $keys ) ) { + foreach( $combinaisonAttributes as $attribute ) { + $combinaison[ $stringified ][ $attribute ] += (float) $product->$attribute; + } + } else { + $rawProduct = $product->toArray(); + + unset( $rawProduct[ 'id' ] ); + unset( $rawProduct[ 'created_at' ] ); + unset( $rawProduct[ 'updated_at' ] ); + unset( $rawProduct[ 'procurement_product_id' ] ); + + $combinaison[ $stringified ] = $rawProduct; + } + }); + + /** + * that's nasty. + */ + return collect( json_decode( json_encode( $combinaison ) ) ); } return $this->products()->get(); } - - public function getCombinedProductsAttribute() - { - $combinaison = []; - - $this->products()->with( 'unit' )->get()->each( function( $product ) use ( &$combinaison ){ - $values = $product->toArray(); - - extract( $values ); - - $keys = array_keys( $combinaison ); - $stringified = Hook::filter( 'ns-products-combinaison-identifier', $product_id . '-' . $order_id . '-' . $discount . '-' . $product_category_id . '-' . $status, $product ); - $combinaisonAttributes = Hook::filter( 'ns-products-combinaison-attributes', [ - 'quantity', - 'total_gross_price', - 'total_price', - 'total_purchase_price', - 'total_net_price', - 'discount' - ]); - - if ( in_array( $stringified, $keys ) ) { - foreach( $combinaisonAttributes as $attribute ) { - $combinaison[ $stringified ][ $attribute ] += (float) $product->$attribute; - } - } else { - $rawProduct = $product->toArray(); - - unset( $rawProduct[ 'id' ] ); - unset( $rawProduct[ 'created_at' ] ); - unset( $rawProduct[ 'updated_at' ] ); - unset( $rawProduct[ 'procurement_product_id' ] ); - - $combinaison[ $stringified ] = $rawProduct; - } - }); - - /** - * that's nasty. - */ - return collect( json_decode( json_encode( $combinaison ) ) ); - } } \ No newline at end of file diff --git a/app/Services/ExpenseService.php b/app/Services/ExpenseService.php index 806a29820..840503987 100755 --- a/app/Services/ExpenseService.php +++ b/app/Services/ExpenseService.php @@ -413,7 +413,7 @@ public function handleProcurementExpense( Procurement $procurement ) * @param OrderProduct $orderProduct * @return void */ - public function createExpenseFromRefund( OrderProductRefund $orderProductRefund, OrderProduct $orderProduct ) + public function createExpenseFromRefund( Order $order, OrderProductRefund $orderProductRefund, OrderProduct $orderProduct ) { $expenseCategory = ExpenseCategory::find( ns()->option->get( 'ns_sales_refunds_account' ) ); @@ -440,6 +440,7 @@ public function createExpenseFromRefund( OrderProductRefund $orderProductRefund, $expense->active = true; $expense->operation = CashFlow::OPERATION_DEBIT; $expense->author = Auth::id(); + $expense->order_id = $order->id; $expense->order_refund_id = $orderProductRefund->order_refund_id; $expense->name = sprintf( __( 'Refunding : %s' ), $orderProduct->name ); $expense->id = 0; // this is not assigned to an existing expense @@ -469,17 +470,19 @@ public function createExpenseFromRefund( OrderProductRefund $orderProductRefund, ns()->option->set( $optionName, $expenseCategory->id ); } - $expense = new Expense; - $expense->value = $orderProductRefund->total_price; - $expense->active = true; - $expense->operation = $orderProduct->condition === OrderProductRefund::CONDITION_DAMAGED ? CashFlow::OPERATION_DEBIT : CashFlow::OPERATION_CREDIT; - $expense->author = Auth::id(); - $expense->order_refund_id = $orderProductRefund->order_refund_id; - $expense->name = sprintf( __( 'Stock Return (%s) : %s' ), $conditionLabel, $orderProduct->name ); - $expense->id = 0; // this is not assigned to an existing expense - $expense->category = $expenseCategory; - - $this->recordCashFlowHistory( $expense ); + if ( OrderProductRefund::CONDITION_DAMAGED ) { + $expense = new Expense; + $expense->value = $orderProductRefund->total_price; + $expense->active = true; + $expense->operation = CashFlow::OPERATION_DEBIT; + $expense->author = Auth::id(); + $expense->order_refund_id = $orderProductRefund->order_refund_id; + $expense->name = sprintf( __( 'Stock Return (%s) : %s' ), $conditionLabel, $orderProduct->name ); + $expense->id = 0; // this is not assigned to an existing expense + $expense->category = $expenseCategory; + + $this->recordCashFlowHistory( $expense ); + } } public function handleCashRegisterHistory( RegisterHistory $history ) diff --git a/app/Services/OrdersService.php b/app/Services/OrdersService.php index f71daaf48..1928ae954 100755 --- a/app/Services/OrdersService.php +++ b/app/Services/OrdersService.php @@ -2036,7 +2036,11 @@ public function deleteOrder(Order $order) { event( new OrderBeforeDeleteEvent( $order ) ); - $order->products->each( function( OrderProduct $product) { + $order + ->products() + ->get() + ->each( function( OrderProduct $product) { + /** * we do proceed by doing an initial return * only if the product is not a quick product/service diff --git a/app/Services/TestService.php b/app/Services/TestService.php index 22c818608..c5c0a609c 100644 --- a/app/Services/TestService.php +++ b/app/Services/TestService.php @@ -26,7 +26,7 @@ public function prepareOrder( Carbon $date, array $orderDetails = [], array $pro $shippingFees = $faker->randomElement([10,15,20,25,30,35,40]); $discountRate = $faker->numberBetween(0,5); - $products = $products->map( function( $product ) use ( $faker, $productDetails ) { + $products = $products->map( function( $product ) use ( $faker, $productDetails, $config ) { $unitElement = $faker->randomElement( $product->unit_quantities ); $data = array_merge([ @@ -38,7 +38,7 @@ public function prepareOrder( Carbon $date, array $orderDetails = [], array $pro 'unit_id' => $unitElement->unit_id, ], $productDetails ); - if ( $faker->randomElement([ false, true ]) ) { + if ( $faker->randomElement([ false, true ]) || ! ( $config[ 'allow_quick_products' ] ?? true ) ) { $data[ 'product_id' ] = $product->id; $data[ 'unit_quantity_id' ] = $unitElement->id; } diff --git a/resources/views/pages/dashboard/orders/templates/_receipt.blade.php b/resources/views/pages/dashboard/orders/templates/_receipt.blade.php index 2fba204ae..a8530b40a 100755 --- a/resources/views/pages/dashboard/orders/templates/_receipt.blade.php +++ b/resources/views/pages/dashboard/orders/templates/_receipt.blade.php @@ -26,7 +26,7 @@ - @foreach( Hook::filter( 'ns-receipt-products', $order->products ) as $product ) + @foreach( Hook::filter( 'ns-receipt-products', $order->combinedProducts ) as $product ) {{ $product->name }} (x{{ $product->quantity }}) diff --git a/tests/Feature/CombiningProductsTest.php b/tests/Feature/CombiningProductsTest.php index a65491bbb..f01d23e92 100644 --- a/tests/Feature/CombiningProductsTest.php +++ b/tests/Feature/CombiningProductsTest.php @@ -24,13 +24,16 @@ public function test_combined_products() Role::namespace( 'admin' )->users->first(), ['*'] ); + + ns()->option->set( 'ns_invoice_merge_similar_products', 'yes' ); $testService = new TestService; $orderDetails = $testService->prepareOrder( ns()->date->now(), [], [], [ 'products' => function() { $product = Product::where( 'tax_group_id', '>', 0 )->with( 'unit_quantities' )->first(); return collect([ $product, $product ]); - } + }, + 'allow_quick_products' => false ]); $response = $this->withSession( $this->app[ 'session' ]->all() ) diff --git a/tests/Feature/OrderRefundTest.php b/tests/Feature/OrderRefundTest.php index 5b2ecb4d1..ea525235a 100755 --- a/tests/Feature/OrderRefundTest.php +++ b/tests/Feature/OrderRefundTest.php @@ -139,9 +139,12 @@ public function testRefund() * We'll keep original products amounts and quantity * this means we're doing a full refund of price and quantities */ - $responseData[ 'data' ][ 'order' ][ 'products' ][0][ 'condition' ] = OrderProductRefund::CONDITION_DAMAGED; - $responseData[ 'data' ][ 'order' ][ 'products' ][0][ 'quantity' ] = 1; - $responseData[ 'data' ][ 'order' ][ 'products' ][0][ 'description' ] = __( 'The product wasn\'t properly manufactured, causing external damage to the device during the shipment.' ); + $responseData[ 'data' ][ 'order' ][ 'products' ] = collect( $responseData[ 'data' ][ 'order' ][ 'products' ] )->map( function( $product ) { + $product[ 'condition' ] = OrderProductRefund::CONDITION_DAMAGED; + $product[ 'quantity' ] = 1; + $product[ 'description' ] = __( 'Test : The product wasn\'t properly manufactured, causing external damage to the device during the shipment.' ); + return $product; + })->toArray(); $response = $this->withSession( $this->app[ 'session' ]->all() ) ->json( 'POST', 'api/nexopos/v4/orders/' . $responseData[ 'data' ][ 'order' ][ 'id' ] . '/refund', [ @@ -181,10 +184,11 @@ public function testRefund() throw new Exception( __( 'An expense hasn\'t been created after the refund.' ) ); } - $expense = $expenseCategory->cashFlowHistories()->orderBy( 'id', 'desc' )->first(); + $expenseValue = $expenseCategory->cashFlowHistories() + ->where( 'order_id', $responseData[ 'data' ][ 'order' ][ 'id' ] ) + ->sum( 'value' ); - - if ( ( float ) $expense->getRawOriginal( 'value' ) != ( float ) $responseData[ 'data' ][ 'orderRefund' ][ 'total' ] ) { + if ( ( float ) $expenseValue != ( float ) $responseData[ 'data' ][ 'orderRefund' ][ 'total' ] ) { throw new Exception( __( 'The expense created after the refund doesn\'t match the order refund total.' ) ); }