Untitled

mail@pastecode.io avatar
unknown
plain_text
14 days ago
43 kB
1
Indexable
Never
<?php

namespace App\Http\Controllers;

use App\Models\Bill;
use App\Models\Ledger;
use App\Models\Product;
use App\Models\Inventory;
use App\Models\AccountHead;
use Illuminate\Support\Str;
use App\Http\Requests\ListRequest;
use Illuminate\Support\Facades\DB;
use App\Http\Resources\Bill\BillResource;
use App\Http\Requests\Bill\BillCreateRequest;
use App\Http\Requests\Bill\BillUpdateRequest;
use App\Http\Resources\Bill\BillListResource;
use App\Models\BillProductAdditionalCostTerm;
use App\Http\Resources\TransactionAccountHeadResource;

class BillController extends BaseController
{
    protected $accountHeadInstance, $productInstance, $ledgerInstance, $inventoryInstance;

    public function __construct()
    {
        parent::__construct(new Bill(), 'Bill', BillListResource::class, BillResource::class);
        $this->accountHeadInstance = new AccountHead();
        $this->productInstance = new Product();
        $this->ledgerInstance = new Ledger();
        $this->inventoryInstance = new Inventory();
    }

    public function index()
    {
        app(ListRequest::class);
        $condition = commonCondition();
        unset($condition['searchKeyword']);
        $bills = $this->model->when(request()->vendor_id, function ($q) {
            $q->where('vendor_id', request()->vendor_id)->when(!isset(request()->multiple_status), function ($q) {
                $q->where('status', '<>', DRAFT)->where('status', '<>', PAID)->where('status', '<>', VOID);
            });
        })->when(request()->multiple_status && count(request()->multiple_status) > 0, function ($q) {
            $q->whereIn('status', request()->multiple_status);
        })->when(isset(request()->search_keyword) && request()->search_keyword != null, function ($q) {
            $q->whereHas('vendor', function ($q) {
                $q->where('name', 'like', '%' . request()->search_keyword . '%');
            });
        });
        if (isset(request()->date) && isset(request()->date[0]) && request()->date[0] != '' && isset(request()->date[1]) && request()->date[1] != '') {
            $condition['betweenCondition'][] = [
                'columnName' => 'bill_date',
                'value' => request()->date,
            ];
        }
        $bills = queryFilter($bills, $condition);
        $bills = (isset($condition['paginate']) && $condition['paginate'] == 1) ? $bills->paginate($condition['limit'] ?? 10) : $bills->get();
        return responseSuccess(new BillListResource($bills), 'Bills.', 200);
    }

    public function show($identifier)
    {
        parent::setRelation(['products', 'ledgers.accountHead', 'paymentAllocations', 'billProductAdditionalCostTerms', 'billProductAdditionalCostTerms.bill', 'billProductAdditionalCostTerms.product', 'billProductAdditionalCostTerms.additionalCostTerm']);
        return parent::show($identifier);
    }

    public function store()
    {
        $request = app(BillCreateRequest::class);
        // dd($request->all());
        DB::beginTransaction();

        $data = $request->only(
            'bill_number',
            'vendor_id',
            'reference_number',
            'bill_date',
            'due_date',
            'billing_address',
            'note',
            'status',
            'discount',
            'discount_type',
            'is_import',
            'country',
            'import_date',
            'document_no',
            'is_product_wise',
        );

        $data['bill_number'] = prefixNumber($this->model) ?? Str::random(8);

        $data['vendor_detail'] = $this->accountHeadInstance->find($data['vendor_id']) ? new TransactionAccountHeadResource($this->accountHeadInstance->find($data['vendor_id'])) : '';

        $bill = $this->model->create($data);

        $products = [];
        $subTotal = 0;
        $totalDiscountedAmount = 0;
        $totalAfterTaxAmount = 0;
        $totalDiscount = 0;
        $totalRatioDiscount = 0;
        $totalTaxAmount = 0;
        $totalTaxableAccount = 0;
        $totalNonTaxableAccount = 0;
        $totalRatioDiscountedAmount = 0;
        $totalRatioDiscount = 0;


        //
        $total_amount_pre_discount = 0;
        $total_amount_pre_discount = array_reduce($request->products, function ($carry, $product) {
            return $carry + ($product['quantity'] * $product['rate']);
        }, 0);
        // $total_quantity = 0;
        // $total_quantity = array_reduce($request->products, function ($carry, $product) {
        //     return $carry + ($product['rate']);
        // }, 0);
        //

        foreach ($request->products as $item) {
            $product = $this->productInstance->find($item['product_id']);
            if ($product->is_service == 1 && $item['account_head_id'] != purchaseServices()) {
                return responseError("The selected ledger for product {$product->name}({$product->id}) is invalid.", 433);
            }
            if ($product->is_service == 0 && $item['account_head_id'] != purchaseGoods()) {
                return responseError("The selected ledger for product {$product->name}({$product->id}) is invalid.", 433);
            }

            $discount = isset($item['discount']) ? $item['discount'] : 0;
            //
            $discount_total = 0;
            $discount_per_product = 0;
            $discount_per_unit = 0;
            $modified_rate = 0;
            $cost_term_amount_all_product = 0;
            $cost_term_amount_per_product = 0;
            $cost_term_amount_per_product_per_unit = 0;
            $cost_term_amount_per_product_total = 0;

            // if (isset($item['discount']) && $item['discount']) {
            //     $discount = $item['discount'];
            // } else {
            // }
            if ($request->discount_type == 'fixed') {
                $discount_per_product = (((($item['quantity'] * $item['rate']) / $total_amount_pre_discount) * $request->discount));
                $discount_per_unit = $discount_per_product / $item['quantity'];
            } elseif ($request->discount_type == 'percent') {
                $discount_total = $total_amount_pre_discount * ($request->discount / 100);
                $discount_per_product = (((($item['quantity'] * $item['rate']) / $total_amount_pre_discount) * $discount_total));
                $discount_per_unit = $discount_per_product / $item['quantity'];
            }
            $modified_rate = $item['rate'] - $discount_per_unit;
            $item['modified_rate'] = $modified_rate;
            //
            foreach ($request->additional_cost_terms as $item_term) {
                if ($item_term['product_id'] && !$item_term['type'] && $product->id == $item_term['product_id']) {
                    $product_term = $this->productInstance->find($item_term['product_id']);
                    if ($product_term->is_service == 1 && $item['account_head_id'] != purchaseServices()) {
                        return responseError("The selected ledger for product {$product_term->name}({$product_term->id}) is invalid.", 433);
                    }
                    if ($product_term->is_service == 0 && $item['account_head_id'] != purchaseGoods()) {
                        return responseError("The selected ledger for product {$product_term->name}({$product_term->id}) is invalid.", 433);
                    }
                    $cost_term_amount_per_product = isset($item_term['amount']) ? $item_term['amount'] : 0;
                    $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
                    $cost_term_amount_per_product_total += $cost_term_amount_per_product;

                    $modified_rate += $cost_term_amount_per_product_per_unit;
                    $item['modified_rate'] = $modified_rate;
                } elseif (!$item_term['product_id'] && $item_term['type']) {
                    $cost_term_amount_all_product = isset($item_term['amount']) ? $item_term['amount'] : 0;
                    if ($item_term['type'] == 'value') {
                        $cost_term_amount_per_product = (((($item['quantity'] * $item['rate']) / $total_amount_pre_discount) * $cost_term_amount_all_product));
                        $cost_term_amount_per_product_total += $cost_term_amount_per_product;
                        $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
                        $modified_rate += $cost_term_amount_per_product_per_unit;
                        $item['modified_rate'] = $modified_rate;
                    } elseif ($item_term['type'] == 'quantity') {
                        // $cost_term_amount_per_product = (((($item['quantity']) / $total_quantity) * $cost_term_amount_all_product));
                        // $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
                        // $modified_rate -= $cost_term_amount_per_product_per_unit;
                        // $item['modified_rate'] = $modified_rate;
                    }
                }
            }
            //

            $amount = $item['quantity'] * $item['rate'];
            // $amount = $item['quantity'] * $item['modified_rate'];
            $discountedAmount = $amount - $discount;
            $ratioDiscountedAmount = $discountedAmount - $discount_per_product;
            $taxAmount = 0;
            if ($item['tax'] == 13) {
                // $taxAmount = 13 / 100 * $discountedAmount;
                $taxAmount = 13 / 100 * $ratioDiscountedAmount;
            }
            // $afterTaxAmount = $discountedAmount + $taxAmount;
            $afterTaxAmount = $ratioDiscountedAmount + $taxAmount;
            $products[$item['product_id']] = [
                'product_detail' => $product,
                'quantity' => $item['quantity'],
                'rate' => $item['rate'],
                'tax' => $item['tax'],
                'discount' => $discount,
                'amount' => $afterTaxAmount,
                'description' => $item['description'] ?? '',
                'account_head_id' => $item['account_head_id'],
                'warehouse_id' => $item['warehouse_id'] ?? null,
                'extra' => json_encode([
                    'discountedAmount' => $discountedAmount,
                    'ratioDiscount' => $discount_per_product,
                    'ratioDiscountedAmount' => $ratioDiscountedAmount,
                    'taxAmount' => $taxAmount,
                    'afterTaxAmount' => $afterTaxAmount,
                ]),
                'modified_rate' => $modified_rate,
            ];
            $subTotal = $subTotal + $amount;
            $totalDiscount = $totalDiscount + $discount;
            $totalRatioDiscount = $totalRatioDiscount + $discount_per_product;
            $totalDiscountedAmount = $totalDiscountedAmount + $discountedAmount;
            $totalRatioDiscountedAmount = $totalRatioDiscountedAmount + $ratioDiscountedAmount;
            $totalTaxAmount = $totalTaxAmount + $taxAmount;
            $totalAfterTaxAmount = $totalAfterTaxAmount + $afterTaxAmount;
            if ($item['tax'] == 13) {
                // $totalTaxableAccount = $totalTaxableAccount + $discountedAmount;
                $totalTaxableAccount = $totalTaxableAccount + $ratioDiscountedAmount;
            } else {
                // $totalNonTaxableAccount = $totalNonTaxableAccount + $discountedAmount;
                $totalNonTaxableAccount = $totalNonTaxableAccount + $ratioDiscountedAmount;
            }
        }
        $bill->products()->attach($products);

        $bill->amount = $totalAfterTaxAmount;
        $bill->due_amount = $totalAfterTaxAmount;
        $bill->extra = [
            'subTotal' => $subTotal,
            'totalDiscount' => $totalDiscount,
            'totalDiscountedAmount' => $totalDiscountedAmount,
            'totalRatioDiscount' => $totalRatioDiscount,
            'totalRatioDiscountedAmount' => $totalRatioDiscountedAmount,
            'totalTaxableAccount' => $totalTaxableAccount,
            'totalNonTaxableAccount' => $totalNonTaxableAccount,
            'totalTaxAmount' => $totalTaxAmount,
            'grandTotal' => $totalAfterTaxAmount
        ];
        $bill->save();

        $actWithBillId = array_map(function ($term) use ($bill) {
            $term['bill_id'] = $bill->id;
            $term['created_at'] =  now();
            $term['updated_at'] =  now();            // $term['act_id'] = $term['additional_cost_term_id'];
            return $term;
        }, $request->additional_cost_terms);
        $bill->billProductAdditionalCostTerms()->insert($actWithBillId);
        DB::commit();
        return responseSuccess(new BillResource($bill->load('products', 'paymentAllocations')), 'Bill has been created.');
    }

    public function update($identifier)
    {
        $request = app(BillUpdateRequest::class);
        DB::beginTransaction();
        $bill = $this->findOrFail($identifier);
        if ($bill->status != DRAFT) {
            return responseError('Only bills with draft status can be edited.');
        }

        $data = $request->only(
            'bill_number',
            'vendor_id',
            'reference_number',
            'bill_date',
            'due_date',
            'billing_address',
            'note',
            'status',
            'discount',
            'discount_type',
            'is_import',
            'country',
            'import_date',
            'document_no',
            'is_product_wise',
        );

        $data['vendor_detail'] = $this->accountHeadInstance->find($data['vendor_id']) ? new TransactionAccountHeadResource($this->accountHeadInstance->find($data['vendor_id'])) : '';

        $bill->update($data);

        $products = [];
        $subTotal = 0;
        $totalDiscountedAmount = 0;
        $totalAfterTaxAmount = 0;
        $totalDiscount = 0;
        $totalTaxAmount = 0;
        $totalTaxableAccount = 0;
        $totalNonTaxableAccount = 0;
        $totalRatioDiscountedAmount = 0;
        $totalRatioDiscount = 0;

        //
        $total_amount_pre_discount = 0;
        $total_amount_pre_discount = array_reduce($request->products, function ($carry, $product) {
            return $carry + ($product['quantity'] * $product['rate']);
        }, 0);
        $total_quantity = 0;
        $total_quantity = array_reduce($request->products, function ($carry, $product) {
            return $carry + ($product['rate']);
        }, 0);
        //

        foreach ($request->products as $item) {
            $product = $this->productInstance->find($item['product_id']);
            if ($product->is_service == 1 && $item['account_head_id'] != purchaseServices()) {
                return responseError("The selected ledger for product {$product->name}({$product->id}) is invalid.", 433);
            }
            if ($product->is_service == 0 && $item['account_head_id'] != purchaseGoods()) {
                return responseError("The selected ledger for product {$product->name}({$product->id}) is invalid.", 433);
            }

            $discount = isset($item['discount']) ? $item['discount'] : 0;
            //
            $discount_total = 0;
            $discount_per_product = 0;
            $discount_per_unit = 0;
            $modified_rate = 0;
            $cost_term_amount_all_product = 0;
            $cost_term_amount_per_product = 0;
            $cost_term_amount_per_product_per_unit = 0;
            $cost_term_amount_per_product_total = 0;

            // if (isset($item['discount']) && $item['discount']) {
            //     $discount = $item['discount'];
            // } else {
            // }
            if ($request->discount_type == 'fixed' || !$request->discount_type) {
                $discount_per_product = (((($item['quantity'] * $item['rate']) / $total_amount_pre_discount) * $request->discount));
                $discount_per_unit = $discount_per_product / $item['quantity'];
            } elseif ($request->discount_type == 'percent') {
                $discount_total = $total_amount_pre_discount * ($request->discount / 100);
                $discount_per_product = (((($item['quantity'] * $item['rate']) / $total_amount_pre_discount) * $discount_total));
                $discount_per_unit = $discount_per_product / $item['quantity'];
            }
            $modified_rate = $item['modified_rate'] = $item['rate'] - $discount_per_unit;
            //
            foreach ($request->additional_cost_terms as $item_term) {
                if ($item_term['product_id'] && !$item_term['type'] && $product->id == $item_term['product_id']) {
                    $product_term = $this->productInstance->find($item_term['product_id']);
                    if ($product_term->is_service == 1 && $item['account_head_id'] != purchaseServices()) {
                        return responseError("The selected ledger for product {$product_term->name}({$product_term->id}) is invalid.", 433);
                    }
                    if ($product_term->is_service == 0 && $item['account_head_id'] != purchaseGoods()) {
                        return responseError("The selected ledger for product {$product_term->name}({$product_term->id}) is invalid.", 433);
                    }
                    $cost_term_amount_per_product = isset($item_term['amount']) ? $item_term['amount'] : 0;
                    $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
                    $cost_term_amount_per_product_total += $cost_term_amount_per_product;

                    $modified_rate += $cost_term_amount_per_product_per_unit;
                    $item['modified_rate'] = $modified_rate;
                } elseif (!$item_term['product_id'] && $item_term['type']) {
                    $cost_term_amount_all_product = isset($item_term['amount']) ? $item_term['amount'] : 0;
                    if ($item_term['type'] == 'value') {
                        $cost_term_amount_per_product = (((($item['quantity'] * $item['rate']) / $total_amount_pre_discount) * $cost_term_amount_all_product));
                        $cost_term_amount_per_product_total += $cost_term_amount_per_product;
                        $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
                        $modified_rate += $cost_term_amount_per_product_per_unit;
                        $item['modified_rate'] = $modified_rate;
                    } elseif ($item_term['type'] == 'quantity') {
                        // $cost_term_amount_per_product = (((($item['quantity']) / $total_quantity) * $cost_term_amount_all_product));
                        // $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
                        // $modified_rate -= $cost_term_amount_per_product_per_unit;
                        // $item['modified_rate'] = $modified_rate;
                    }
                }
            }
            //

            $amount = $item['quantity'] * $item['rate'];
            // $amount = $item['quantity'] * $item['modified_rate'];
            $discountedAmount = $amount - $discount;
            $ratioDiscountedAmount = $discountedAmount - $discount_per_product;
            $taxAmount = 0;
            if ($item['tax'] == 13) {
                // $taxAmount = 13 / 100 * $discountedAmount;
                $taxAmount = 13 / 100 * $ratioDiscountedAmount;
            }
            // $afterTaxAmount = $discountedAmount + $taxAmount;
            $afterTaxAmount = $ratioDiscountedAmount + $taxAmount;
            $products[$item['product_id']] = [
                'product_detail' => $this->productInstance->find($item['product_id']),
                'quantity' => $item['quantity'],
                'rate' => $item['rate'],
                'tax' => $item['tax'],
                'discount' => $discount,
                'amount' => $afterTaxAmount,
                'description' => $item['description'] ?? '',
                'account_head_id' => $item['account_head_id'],
                'warehouse_id' => $item['warehouse_id'] ?? null,
                'extra' => json_encode([
                    'discountedAmount' => $discountedAmount,
                    'ratioDiscount' => $discount_per_product,
                    'ratioDiscountedAmount' => $ratioDiscountedAmount,
                    'taxAmount' => $taxAmount,
                    'afterTaxAmount' => $afterTaxAmount,
                ]),
                'modified_rate' => $modified_rate,
            ];
            $subTotal = $subTotal + $amount;
            $totalDiscount = $totalDiscount + $discount;
            $totalRatioDiscount = $totalRatioDiscount + $discount_per_product;
            $totalDiscountedAmount = $totalDiscountedAmount + $discountedAmount;
            $totalRatioDiscountedAmount = $totalRatioDiscountedAmount + $ratioDiscountedAmount;
            $totalTaxAmount = $totalTaxAmount + $taxAmount;
            $totalAfterTaxAmount = $totalAfterTaxAmount + $afterTaxAmount;
            if ($item['tax'] == 13) {
                // $totalTaxableAccount = $totalTaxableAccount + $discountedAmount;
                $totalTaxableAccount = $totalTaxableAccount + $ratioDiscountedAmount;
            } else {
                // $totalNonTaxableAccount = $totalNonTaxableAccount + $discountedAmount;
                $totalNonTaxableAccount = $totalNonTaxableAccount + $ratioDiscountedAmount;
            }
        }
        $bill->products()->sync($products);
        $bill->amount = $totalAfterTaxAmount;
        $bill->due_amount = $totalAfterTaxAmount;
        $bill->extra = [
            'subTotal' => $subTotal,
            'totalDiscount' => $totalDiscount,
            'totalDiscountedAmount' => $totalDiscountedAmount,
            'totalRatioDiscount' => $totalRatioDiscount,
            'totalRatioDiscountedAmount' => $totalRatioDiscountedAmount,
            'totalTaxableAccount' => $totalTaxableAccount,
            'totalNonTaxableAccount' => $totalNonTaxableAccount,
            'totalTaxAmount' => $totalTaxAmount,
            'grandTotal' => $totalAfterTaxAmount
        ];
        $bill->save();
        // $actWithBillId = array_map(function ($term) use ($bill) {
        //     $term['bill_id'] = $bill->id;
        //     $term['created_at'] =  now();
        //     $term['updated_at'] =  now();
        //     // if (!isset($term['product_id']) || !$term['product_id']) {
        //     //     $term['product_id'] = -1;
        //     // }
        //     // if (!isset($term['type']) || !$term['type']) {
        //     //     $term['type'] = -1;
        //     // }
        //     return $term;
        // }, $request->additional_cost_terms);
        $termsToKeep = [];
        foreach ($request->additional_cost_terms as $key => $value) {
            $value['bill_id'] = $bill->id;
            $value['created_at'] =  now();
            $value['updated_at'] =  now();
            $record =  $bill->billProductAdditionalCostTerms()->updateOrCreate(
                [
                    'bill_id' => $value['bill_id'],
                    'act_id' => $value['act_id'],
                    'product_id' => $value['product_id'],
                    'type' => $value['type'],
                ],
                [
                    'amount' =>  $value['amount'],
                    // 'created_at' =>  $value['created_at'],
                    'updated_at' =>  $value['updated_at'],
                    'paid_account_id' =>  $value['paid_account_id'],
                ]
            );
            $termsToKeep[] = $record->id;
        }
        // $bill->billProductAdditionalCostTerms()->upsert(
        // BillProductAdditionalCostTerm::upsert(
        //     $actWithBillId,
        //     ['bill_id', 'act_id', 'product_id', 'type'],
        //     ['amount', 'updated_at']
        // );
        $requestIds = array_map(function ($term) {
            return $term['act_id'];
        }, $request->additional_cost_terms);
        $bill->billProductAdditionalCostTerms()->where('bill_id', $bill->id)
            // ->whereNotIn('act_id', $requestIds)
            ->whereNotIn('id', $termsToKeep)
            ->delete();
        DB::commit();
        return responseSuccessMsg('Bill has been updated.');
    }

    public function destroy($identifier)
    {
        $bill = $this->findOrFail($identifier);
        if ($bill->status != DRAFT) {
            return responseError('Only bills with draft status can be deleted.');
        }
        $bill->billProductAdditionalCostTerms()->delete();

        return parent::destroy($identifier);
    }

    public function approveStatus($identifier)
    {
        DB::beginTransaction();
        $bill = $this->findOrFail($identifier);
        if ($bill->status == UNPAID) {
            return responseError('Bill status has already been approved.');
        }
        if ($bill->status == PAID) {
            return responseError('Bill status has already been approved.');
        }
        if ($bill->status == VOID) {
            return responseError('Bill status has already been rendered void.');
        }
        $totalDiscountedAmount = 0;
        $totalAfterTaxAmount = 0;
        $totalDiscount = 0;
        $totalTaxAmount = 0;
        //
        $total_amount_pre_discount = 0;
        $total_amount_pre_discount = array_reduce($bill->products->toArray(), function ($carry, $product) {
            $quantity = $product['pivot']['quantity'];
            $rate = (float)$product['pivot']['rate'];
            return $carry + ($quantity * $rate);
        }, 0);
        //
        foreach ($bill->products as $item) {
            //
            $discount_total = 0;
            $discount_per_product = 0;
            $discount_per_unit = 0;
            $modified_rate = 0;
            $cost_term_amount_all_product = 0;
            $cost_term_amount_per_product = 0;
            $cost_term_amount_per_product_per_unit = 0;
            $cost_term_amount_per_product_total = 0;
            $modified_rate_adc = 0;

            if ($bill->discount_type == 'fixed' || !$bill->discount_type) {
                $discount_per_product = (((($item->pivot->quantity * $item->pivot->rate) / $total_amount_pre_discount) * $bill->discount));
                $discount_per_unit = $discount_per_product / $item->pivot->quantity;
            } elseif ($bill->discount_type == 'percent') {
                $discount_total = $total_amount_pre_discount * ($bill->discount / 100);
                $discount_per_product = (((($item->pivot->quantity * $item->pivot->rate) / $total_amount_pre_discount) * $discount_total));
                $discount_per_unit = $discount_per_product / $item->pivot->quantity;
            }
            $modified_rate  = $item->pivot->rate - $discount_per_unit;

            //
            // foreach ($bill->billProductAdditionalCostTerms as $item_term) {
            //     $product = $this->productInstance->find($item->product_id);
            //     if ($item_term->product_id && !$item_term->type && $product->id == $item_term->product_id) {
            //         $product_term = $this->productInstance->find($item_term->product_id);
            //         $cost_term_amount_per_product = isset($item_term->amount) ? $item_term->amount : 0;
            //         $cost_term_amount_per_product_total += $cost_term_amount_per_product;
            //         $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
            //         $modified_rate += $cost_term_amount_per_product_per_unit;
            //         $modified_rate_adc = $modified_rate;
            //     } elseif (!$item_term->product_id && $item_term->type) {
            //         $cost_term_amount_all_product = isset($item_term->amount) ? $item_term->amount : 0;
            //         if ($item_term->type == 'value') {
            //             $cost_term_amount_per_product = (((($item->quantity * $item->rate) / $total_amount_pre_discount) * $cost_term_amount_all_product));
            //             $cost_term_amount_per_product_total += $cost_term_amount_per_product;
            //             $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item->quantity;
            //             $modified_rate += $cost_term_amount_per_product_per_unit;
            //             $modified_rate_adc = $modified_rate;
            //         } elseif ($item_term->type == 'quantity') {
            //             // $cost_term_amount_per_product = (((($item->quantity * $item->rate) / $total_amount_pre_discount) * $cost_term_amount_all_product));
            //             // $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item->quantity;
            //             // $modified_rate -= $cost_term_amount_per_product_per_unit;
            //         }
            //     }
            // }
            //
            // dd($discount_per_product);
            $amount = $item->pivot->quantity * $item->pivot->rate;
            $discountedAmount = $amount - $item->pivot->discount;
            $ratioDiscountedAmount = $discountedAmount - $discount_per_product;
            // $ratioDiscountedAmount = $ratioDiscountedAmount - $cost_term_amount_per_product_total;
            $taxAmount = 0;
            if ($item->pivot->tax == 13) {
                // $taxAmount = 13 / 100 * $discountedAmount;
                $taxAmount = 13 / 100 * $ratioDiscountedAmount;
            }
            // $afterTaxAmount = $discountedAmount + $taxAmount;
            $afterTaxAmount = $ratioDiscountedAmount + $taxAmount;
            //

            // // $amount = $item->pivot->quantity * $item->pivot->rate;
            // $amount = $item->pivot->quantity * $item->pivot->modified_rate;
            // $discountedAmount = $amount - $item->pivot->discount ?? 0;
            // $taxAmount = 0;
            // if ($item->pivot->tax == 13) {
            //     $taxAmount = 13 / 100 * $discountedAmount;
            // }

            // ledgerEntry($bill, $discountedAmount, $bill->bill_date, $this->ledgerInstance::DEBITENTRY, $item->pivot->account_head_id, $bill->vendor_id); // product amount
            ledgerEntry($bill, $ratioDiscountedAmount, $bill->bill_date, $this->ledgerInstance::DEBITENTRY, $item->pivot->account_head_id, $bill->vendor_id); // product amount
            if ($taxAmount > 0) {
                ledgerEntry($bill, $taxAmount, $bill->bill_date, $this->ledgerInstance::DEBITENTRY, $this->accountHeadInstance->findBySlug('vat')->id, $bill->vendor_id);
            }
            $totalDiscount = $totalDiscount + $item->pivot->discount;
            $totalDiscountedAmount = $totalDiscountedAmount + $discountedAmount;
            $totalTaxAmount = $totalTaxAmount + $taxAmount;
            $afterTaxAmount = $discountedAmount + $taxAmount;
            $totalAfterTaxAmount = $totalAfterTaxAmount + $afterTaxAmount;

            ledgerEntry($bill, $afterTaxAmount, $bill->bill_date, $this->ledgerInstance::CREDITENTRY, $bill->vendor_id, $item->pivot->account_head_id);

            $product = $this->productInstance->findOrFail($item->pivot->product_id);
            if ($product->inventory != 0) {
                // $inventories = increaseProductRateCalculation($product, $item->pivot->quantity, $item->pivot->rate, $item->pivot->amount);
                $inventories = increaseProductRateCalculation($product, $item->pivot->quantity, $item->pivot->modified_rate, $item->pivot->amount);
                increaseWarehouseCalculation($product, $item->pivot->quantity, $item->pivot->warehouse_id ?? null);
            }
            $item->pivot->update([
                'tracks' => json_encode([
                    'inventory_id' => $inventories->id ?? '',
                    'purchase_quantity' => $item->pivot->quantity,
                    // 'rate' => $item->pivot->rate,
                    'rate' => $item->pivot->modified_rate,
                ])
            ]);
        }

        // foreach ($bill->billProductAdditionalCostTerms as $item_term) {
        //     ledgerEntry($bill, $item_term->amount, $bill->bill_date, $this->ledgerInstance::DEBITENTRY, $item_term->additionalCostTerm->account_head_id, $item_term->paid_account_id);
        //     ledgerEntry($bill, $item_term->amount, $bill->bill_date, $this->ledgerInstance::CREDITENTRY, $item_term->paid_account_id, $item_term->additionalCostTerm->account_head_id);
        // }
        $bill->update(['status' => UNPAID]);
        DB::commit();
        return responseSuccessMsg('Bill status has been changed.');
    }

    public function voidStatus($identifier)
    {
        DB::beginTransaction();
        $bill = $this->findOrFail($identifier);
        if ($bill->return) {
            return responseError('Please void purchase return before purchase bill void');
        }
        switch ($bill->status) {
            case VOID:
                return responseError('Bill status has already been rendered void.');
                break;
            case PAID:
                return responseError('Paid Bills can\'t be void.');
                break;
            case PARTIAL:
                return responseError('Partial Bills can\'t be void.');
                break;
            case RETURNED:
                return responseError('Returned Bills can\'t be void.');
                break;
            case UNPAID:
                $totalDiscountedAmount = 0;
                $totalAfterTaxAmount = 0;
                $totalDiscount = 0;
                $totalTaxAmount = 0;
                //
                $total_amount_pre_discount = 0;
                $total_amount_pre_discount = array_reduce($bill->products->toArray(), function ($carry, $product) {
                    $quantity = $product['pivot']['quantity'];
                    $rate = (float)$product['pivot']['rate'];
                    return $carry + ($quantity * $rate);
                }, 0);
                //
                foreach ($bill->products as $item) {
                    $product = $this->productInstance->findOrFail($item->pivot->product_id);
                    $tracks = json_decode($item->pivot->tracks, true);
                    $inventory = $this->inventoryInstance->findOrFail($tracks['inventory_id']);
                    if ($item->pivot->quantity > $inventory->quantity) {
                        return responseError("Stock limit reached for {$product->name}({$product->id})");
                    }
                    //
                    $discount_total = 0;
                    $discount_per_product = 0;
                    $discount_per_unit = 0;
                    $modified_rate = 0;
                    $cost_term_amount_all_product = 0;
                    $cost_term_amount_per_product = 0;
                    $cost_term_amount_per_product_per_unit = 0;
                    $cost_term_amount_per_product_total = 0;
                    $modified_rate_adc = 0;

                    if ($bill->discount_type == 'fixed' || !$bill->discount_type) {
                        $discount_per_product = (((($item->pivot->quantity * $item->pivot->rate) / $total_amount_pre_discount) * $bill->discount));
                        $discount_per_unit = $discount_per_product / $item->pivot->quantity;
                    } elseif ($bill->discount_type == 'percent') {
                        $discount_total = $total_amount_pre_discount * ($bill->discount / 100);
                        $discount_per_product = (((($item->pivot->quantity * $item->pivot->rate) / $total_amount_pre_discount) * $discount_total));
                        $discount_per_unit = $discount_per_product / $item->pivot->quantity;
                    }
                    $modified_rate  = $item->pivot->rate - $discount_per_unit;
                    //
                    // foreach ($bill->billProductAdditionalCostTerms as $item_term) {
                    //     $product = $this->productInstance->find($item->product_id);
                    //     if ($item_term->product_id && !$item_term->type && $product->id == $item_term->product_id) {
                    //         $product_term = $this->productInstance->find($item_term->product_id);
                    //         $cost_term_amount_per_product = isset($item_term->amount) ? $item_term->amount : 0;
                    //         $cost_term_amount_per_product_total += $cost_term_amount_per_product;
                    //         $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item['quantity'];
                    //         $modified_rate += $cost_term_amount_per_product_per_unit;
                    //         $modified_rate_adc = $modified_rate;
                    //     } elseif (!$item_term->product_id && $item_term->type) {
                    //         $cost_term_amount_all_product = isset($item_term->amount) ? $item_term->amount : 0;
                    //         if ($item_term->type == 'value') {
                    //             $cost_term_amount_per_product = (((($item->quantity * $item->rate) / $total_amount_pre_discount) * $cost_term_amount_all_product));
                    //             $cost_term_amount_per_product_total += $cost_term_amount_per_product;
                    //             $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item->quantity;
                    //             $modified_rate += $cost_term_amount_per_product_per_unit;
                    //             $modified_rate_adc = $modified_rate;
                    //         } elseif ($item_term->type == 'quantity') {
                    //             // $cost_term_amount_per_product = (((($item->quantity * $item->rate) / $total_amount_pre_discount) * $cost_term_amount_all_product));
                    //             // $cost_term_amount_per_product_per_unit = $cost_term_amount_per_product / $item->quantity;
                    //             // $modified_rate -= $cost_term_amount_per_product_per_unit;
                    //         }
                    //     }
                    // }

                    //
                    // dd($discount_per_product);
                    $amount = $item->pivot->quantity * $item->pivot->rate;
                    $discountedAmount = $amount - $item->pivot->discount;
                    $ratioDiscountedAmount = $discountedAmount - $discount_per_product;
                    $taxAmount = 0;
                    if ($item->pivot->tax == 13) {
                        // $taxAmount = 13 / 100 * $discountedAmount;
                        $taxAmount = 13 / 100 * $ratioDiscountedAmount;
                    }
                    // $afterTaxAmount = $discountedAmount + $taxAmount;
                    $afterTaxAmount = $ratioDiscountedAmount + $taxAmount;
                    //

                    // // $amount = $item->pivot->quantity * $item->pivot->rate;
                    // $amount = $item->pivot->quantity * $item->pivot->modified_rate;
                    // $discountedAmount = $amount - $item->pivot->discount ?? 0;
                    // $taxAmount = 0;
                    // if ($item->pivot->tax == 13) {
                    //     $taxAmount = 13 / 100 * $discountedAmount;
                    // }
                    // ledgerEntry($bill, $discountedAmount, $bill->bill_date, $this->ledgerInstance::CREDITENTRY, $item->pivot->account_head_id, $bill->vendor_id); // product amount

                    ledgerEntry($bill, $ratioDiscountedAmount, $bill->bill_date, $this->ledgerInstance::CREDITENTRY, $item->pivot->account_head_id, $bill->vendor_id); // product amount
                    if ($taxAmount > 0) {
                        ledgerEntry($bill, $taxAmount, $bill->bill_date, $this->ledgerInstance::CREDITENTRY, $this->accountHeadInstance->findBySlug('vat')->id, $bill->vendor_id);
                    }
                    $totalDiscount = $totalDiscount + $item->pivot->discount;
                    $totalDiscountedAmount = $totalDiscountedAmount + $discountedAmount;
                    $totalTaxAmount = $totalTaxAmount + $taxAmount;
                    $afterTaxAmount = $discountedAmount + $taxAmount;
                    $totalAfterTaxAmount = $totalAfterTaxAmount + $afterTaxAmount;

                    ledgerEntry($bill, $afterTaxAmount, $bill->bill_date, $this->ledgerInstance::DEBITENTRY, $bill->vendor_id, $item->pivot->account_head_id);

                    if ($product->inventory != 0) {
                        if (rateType() == FIFO) {
                            $inventory->update([
                                'quantity' => $inventory->quantity - $tracks['purchase_quantity'],
                                'amount' => ($inventory->quantity - $tracks['purchase_quantity']) * $inventory->rate,
                            ]);
                        } else {
                            $calculatedQuantity = $inventory->quantity - $item->pivot->quantity;
                            // $calculatedAmount = $inventory->amount - ($item->pivot->quantity * $item->pivot->rate);
                            $calculatedAmount = $inventory->amount - ($item->pivot->quantity * $item->pivot->modified_rate);
                            if ($calculatedQuantity == 0) {
                                $inventory->update([
                                    'quantity' => 0,
                                    'amount' => 0,
                                ]);
                            } else {
                                $inventory->update([
                                    'quantity' => $calculatedQuantity,
                                    'amount' => $calculatedAmount,
                                    'rate' => $calculatedAmount / $calculatedQuantity,
                                ]);
                            }
                        }
                        decreaseWarehouseCalculation($product, $item->pivot->quantity, $item->pivot->warehouse_id ?? null);
                    }
                }
                break;
        }
        $bill->update(['status' => VOID]);
        DB::commit();
        return responseSuccessMsg('Bill status has been changed.');
    }
}
Leave a Comment