<?php

namespace Modules\Connector\Http\Controllers\Api;

use App\Business;
use App\BusinessLocation;
use App\Contact;
use App\Product;
use App\TaxRate;
use App\Transaction;
use App\TransactionPayment;
use App\TransactionSellLine;
use App\Unit;
use App\Utils\BusinessUtil;
use App\Utils\CashRegisterUtil;
use App\Utils\ContactUtil;
use App\Utils\NotificationUtil;
use App\Utils\ProductUtil;
use App\Utils\TransactionUtil;
use App\Variation;
use DB;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Auth;
use Modules\Connector\Transformers\SellResource;

/**
 * @group Sales management
 * @authenticated
 *
 * APIs for managing sales
 */
class SellController extends ApiController
{
    /**
     * All Utils instance.
     */
    protected $contactUtil;

    protected $productUtil;

    protected $businessUtil;

    protected $transactionUtil;

    protected $cashRegisterUtil;

    protected $moduleUtil;

    protected $notificationUtil;

    /**
     * Constructor
     *
     * @param  ProductUtils  $product
     * @return void
     */
    public function __construct(
        ContactUtil $contactUtil,
        ProductUtil $productUtil,
        BusinessUtil $businessUtil,
        TransactionUtil $transactionUtil,
        CashRegisterUtil $cashRegisterUtil,
        NotificationUtil $notificationUtil
    ) {
        $this->contactUtil = $contactUtil;
        $this->productUtil = $productUtil;
        $this->businessUtil = $businessUtil;
        $this->transactionUtil = $transactionUtil;
        $this->cashRegisterUtil = $cashRegisterUtil;
        $this->notificationUtil = $notificationUtil;

        $this->dummyPaymentLine = ['method' => 'cash', 'amount' => 0, 'note' => '', 'card_transaction_number' => '', 'card_number' => '', 'card_type' => '', 'card_holder_name' => '', 'card_month' => '', 'card_year' => '', 'card_security' => '', 'cheque_number' => '', 'bank_account_number' => '',
            'is_return' => 0, 'transaction_no' => '', ];
        parent::__construct();
    }

    /**
     * List sells
     *
     * @queryParam location_id id of the location Example: 1
     * @queryParam contact_id id of the customer
     * @queryParam status Sell status. Available values final, draft, quotation, proforma Example: final
     * @queryParam payment_status Comma separated values of payment statuses. Available values due, partial, paid, overdue Example: due,partial
     * @queryParam start_date format:Y-m-d Example: 2018-06-25
     * @queryParam end_date format:Y-m-d Example: 2018-06-25
     * @queryParam user_id id of the user who created the sale
     * @queryParam service_staff_id id of the service staff assigned with the sale
     * @queryParam shipping_status Shipping Status of the sale ('ordered', 'packed', 'shipped', 'delivered', 'cancelled') Example: ordered
     * @queryParam source Source of the sale
     * @queryParam only_subscriptions Filter only subcription invoices (1, 0)
     * @queryParam send_purchase_details Get purchase details of each sell line (1, 0)
     * @queryParam order_by_date Sort sell list by date ('asc', 'desc') Example: desc
     * @queryParam per_page Total records per page. default: 10, Set -1 for no pagination Example:10
     *
     * @response {
        "data": [
            {
                "id": 6,
                "business_id": 1,
                "location_id": 1,
                "res_table_id": null,
                "res_waiter_id": null,
                "res_order_status": null,
                "type": "sell",
                "sub_type": null,
                "status": "final",
                "is_quotation": 0,
                "payment_status": "paid",
                "adjustment_type": null,
                "contact_id": 4,
                "customer_group_id": null,
                "invoice_no": "AS0001",
                "ref_no": "",
                "source": null,
                "subscription_no": null,
                "subscription_repeat_on": null,
                "transaction_date": "2018-04-10 13:23:21",
                "total_before_tax": "770.0000",
                "tax_id": null,
                "tax_amount": "0.0000",
                "discount_type": "percentage",
                "discount_amount": "0.0000",
                "rp_redeemed": 0,
                "rp_redeemed_amount": "0.0000",
                "shipping_details": null,
                "shipping_address": null,
                "shipping_status": null,
                "delivered_to": null,
                "shipping_charges": "0.0000",
                "additional_notes": null,
                "staff_note": null,
                "round_off_amount": "0.0000",
                "final_total": "770.0000",
                "expense_category_id": null,
                "expense_for": null,
                "commission_agent": null,
                "document": null,
                "is_direct_sale": 0,
                "is_suspend": 0,
                "exchange_rate": "1.000",
                "total_amount_recovered": null,
                "transfer_parent_id": null,
                "return_parent_id": null,
                "opening_stock_product_id": null,
                "created_by": 1,
                "import_batch": null,
                "import_time": null,
                "types_of_service_id": null,
                "packing_charge": null,
                "packing_charge_type": null,
                "service_custom_field_1": null,
                "service_custom_field_2": null,
                "service_custom_field_3": null,
                "service_custom_field_4": null,
                "mfg_parent_production_purchase_id": null,
                "mfg_wasted_units": null,
                "mfg_production_cost": "0.0000",
                "mfg_is_final": 0,
                "is_created_from_api": 0,
                "essentials_duration": "0.00",
                "essentials_duration_unit": null,
                "essentials_amount_per_unit_duration": "0.0000",
                "essentials_allowances": null,
                "essentials_deductions": null,
                "rp_earned": 0,
                "repair_completed_on": null,
                "repair_warranty_id": null,
                "repair_brand_id": null,
                "repair_status_id": null,
                "repair_model_id": null,
                "repair_defects": null,
                "repair_serial_no": null,
                "repair_updates_email": 0,
                "repair_updates_sms": 0,
                "repair_checklist": null,
                "repair_security_pwd": null,
                "repair_security_pattern": null,
                "repair_due_date": null,
                "repair_device_id": null,
                "order_addresses": null,
                "is_recurring": 0,
                "recur_interval": null,
                "recur_interval_type": null,
                "recur_repetitions": null,
                "recur_stopped_on": null,
                "recur_parent_id": null,
                "invoice_token": null,
                "pay_term_number": null,
                "pay_term_type": null,
                "pjt_project_id": null,
                "pjt_title": null,
                "woocommerce_order_id": null,
                "selling_price_group_id": null,
                "created_at": "2018-01-06 07:06:11",
                "updated_at": "2018-01-06 07:06:11",
                "sell_lines": [
                    {
                        "id": 1,
                        "transaction_id": 6,
                        "product_id": 2,
                        "variation_id": 3,
                        "quantity": 10,
                        "mfg_waste_percent": "0.0000",
                        "quantity_returned": "0.0000",
                        "unit_price_before_discount": "70.0000",
                        "unit_price": "70.0000",
                        "line_discount_type": null,
                        "line_discount_amount": "0.0000",
                        "unit_price_inc_tax": "77.0000",
                        "item_tax": "7.0000",
                        "tax_id": 1,
                        "discount_id": null,
                        "lot_no_line_id": null,
                        "sell_line_note": null,
                        "res_service_staff_id": null,
                        "res_line_order_status": null,
                        "woocommerce_line_items_id": null,
                        "parent_sell_line_id": null,
                        "children_type": "",
                        "sub_unit_id": null,
                        "created_at": "2018-01-06 07:06:11",
                        "updated_at": "2018-01-06 07:06:11"
                    }
                ],
                "payment_lines": [
                    {
                        "id": 1,
                        "transaction_id": 6,
                        "business_id": null,
                        "is_return": 0,
                        "amount": "770.0000",
                        "method": "cash",
                        "transaction_no": null,
                        "card_transaction_number": null,
                        "card_number": null,
                        "card_type": "visa",
                        "card_holder_name": null,
                        "card_month": null,
                        "card_year": null,
                        "card_security": null,
                        "cheque_number": null,
                        "bank_account_number": null,
                        "paid_on": "2018-01-09 17:30:35",
                        "created_by": 1,
                        "payment_for": null,
                        "parent_id": null,
                        "note": null,
                        "document": null,
                        "payment_ref_no": null,
                        "account_id": null,
                        "created_at": "2018-01-06 01:36:11",
                        "updated_at": "2018-01-06 01:36:11"
                    }
                ],
                "invoice_url": "http://local.pos.com/invoice/6dfd77eb80f4976b456128e7f1311c9f",
                "payment_link": "http://local.pos.com/pay/6dfd77eb80f4976b456128e7f1311c9f"
            }
        ],
        "links": {
            "first": "http://local.pos.com/connector/api/sell?page=1",
            "last": "http://local.pos.com/connector/api/sell?page=6",
            "prev": null,
            "next": "http://local.pos.com/connector/api/sell?page=2"
        },
        "meta": {
            "current_page": 1,
            "from": 1,
            "path": "http://local.pos.com/connector/api/sell",
            "per_page": 10,
            "to": 10
        }
    }
     */
    public function index()
    {
        //TODO::order by
        $user = Auth::user();
        $business_id = $user->business_id;
        $is_admin = $this->businessUtil->is_admin($user, $business_id);

        if (! $is_admin && ! auth()->user()->hasAnyPermission(['sell.view', 'direct_sell.access', 'direct_sell.view', 'view_own_sell_only', 'view_commission_agent_sell', 'access_shipping', 'access_own_shipping', 'access_commission_agent_shipping'])) {
            abort(403, 'Unauthorized action.');
        }

        $filters = request()->only(['location_id', 'contact_id', 'payment_status', 'start_date', 'end_date', 'user_id', 'service_staff_id', 'only_subscriptions', 'per_page', 'shipping_status', 'order_by_date', 'source', 'status']);

        $with = ['sell_lines', 'payment_lines', 'contact'];
        $query = Transaction::where('business_id', $business_id)
                            ->where('type', 'sell');

        if (! empty(request()->input('send_purchase_details')) && request()->input('send_purchase_details') == 1) {
            $with[] = 'sell_lines.sell_line_purchase_lines';
            $with[] = 'sell_lines.sell_line_purchase_lines.purchase_line';
        }

        $query->with($with);

        $permitted_locations = $user->permitted_locations($business_id);
        if ($permitted_locations != 'all') {
            $query->whereIn('transactions.location_id', $permitted_locations);
        }

        if (! $user->can('direct_sell.view')) {
            $query->where(function ($q) use ($user) {
                if ($user->hasAnyPermission(['view_own_sell_only', 'access_own_shipping'])) {
                    $q->where('transactions.created_by', $user->id);
                }

                //if user is commission agent display only assigned sells
                if ($user->hasAnyPermission(['view_commission_agent_sell', 'access_commission_agent_shipping'])) {
                    $q->orWhere('transactions.commission_agent', $user->id);
                }
            });
        }

        if (! empty($filters['status'])) {
            if ($filters['status'] == 'final' || $filters['status'] == 'draft') {
                $query->where('transactions.status', $filters['status']);
            } elseif ($filters['status'] == 'quotation') {
                $query->where('transactions.sub_status', 'quotation');
            } elseif ($filters['status'] == 'proforma') {
                $query->where('transactions.sub_status', 'proforma');
            }
        }

        if (! empty($filters['location_id'])) {
            $query->where('transactions.location_id', $filters['location_id']);
        }

        if (! empty($filters['contact_id'])) {
            $query->where('transactions.contact_id', $filters['contact_id']);
        }

        $payment_status = [];
        if (! empty($filters['payment_status'])) {
            $payment_status = explode(',', $filters['payment_status']);
        }

        if (! $is_admin) {
            $payment_status_arr = [];
            if (auth()->user()->can('view_paid_sells_only')) {
                $payment_status_arr[] = 'paid';
            }

            if (auth()->user()->can('view_due_sells_only')) {
                $payment_status_arr[] = 'due';
            }

            if (auth()->user()->can('view_partial_sells_only')) {
                $payment_status_arr[] = 'partial';
            }

            if (empty($payment_status_arr)) {
                if (auth()->user()->can('view_overdue_sells_only')) {
                    $query->OverDue();
                }
            } else {
                if (auth()->user()->can('view_overdue_sells_only')) {
                    $query->where(function ($q) use ($payment_status_arr) {
                        $q->whereIn('transactions.payment_status', $payment_status_arr)
                        ->orWhere(function ($qr) {
                            $qr->OverDue();
                        });
                    });
                } else {
                    $query->whereIn('transactions.payment_status', $payment_status_arr);
                }
            }
        }

        if (! empty($payment_status)) {
            $query->where(function ($q) use ($payment_status) {
                $is_overdue = false;
                if (in_array('overdue', $payment_status)) {
                    $is_overdue = true;
                    $key = array_search('overdue', $payment_status);
                    unset($payment_status[$key]);
                }

                if (! empty($payment_status)) {
                    $q->whereIn('transactions.payment_status', $payment_status);
                }

                if ($is_overdue) {
                    $q->orWhere(function ($qr) {
                        $qr->whereIn('transactions.payment_status', ['due', 'partial'])
                            ->whereNotNull('transactions.pay_term_number')
                            ->whereNotNull('transactions.pay_term_type')
                            ->whereRaw("IF(transactions.pay_term_type='days', DATE_ADD(transactions.transaction_date, INTERVAL transactions.pay_term_number DAY) < CURDATE(), DATE_ADD(transactions.transaction_date, INTERVAL transactions.pay_term_number MONTH) < CURDATE())");
                    });
                }
            });
        }

        if (! empty($filters['start_date'])) {
            $query->whereDate('transactions.transaction_date', '>=', $filters['start_date']);
        }

        if (! empty($filters['end_date'])) {
            $query->whereDate('transactions.transaction_date', '<=', $filters['end_date']);
        }

        if (! empty($filters['order_by_date'])) {
            $order_by_date = in_array($filters['order_by_date'], ['asc', 'desc']) ? $filters['order_by_date'] : 'desc';
            $query->orderBy('transactions.transaction_date', $order_by_date);
        }

        if (! empty($filters['user_id'])) {
            $query->where('transactions.created_by', $filters['user_id']);
        }

        if (! empty($filters['service_staff_id'])) {
            $query->where('transactions.res_waiter_id', $filters['service_staff_id']);
        }

        if (! empty($filters['shipping_status'])) {
            $query->where('transactions.shipping_status', $filters['shipping_status']);
        }

        if (! empty($filters['only_subscriptions']) && $filters['only_subscriptions'] == 1) {
            $query->where(function ($q) {
                $q->whereNotNull('transactions.recur_parent_id')
                    ->orWhere('transactions.is_recurring', 1);
            });
        }

        if (! empty($filters['source'])) {
            //only exception for woocommerce
            if ($filters['source'] == 'woocommerce') {
                $query->whereNotNull('transactions.woocommerce_order_id');
            } else {
                $query->where('transactions.source', $filters['source']);
            }
        }

        $perPage = ! empty($filters['per_page']) ? $filters['per_page'] : $this->perPage;
        if ($perPage == -1) {
            $sells = $query->get();
        } else {
            $sells = $query->paginate($perPage);
            $sells->appends(request()->query());
        }

        return SellResource::collection($sells);
    }

    /**
     * Get the specified sell
     *
     * @urlParam sell required comma separated ids of the sells Example: 55
     * @queryParam send_purchase_details Get purchase details of each sell line (1, 0)
     *
     * @response {
        "data": [
            {
                "id": 55,
                "business_id": 1,
                "location_id": 1,
                "res_table_id": 5,
                "res_waiter_id": null,
                "res_order_status": null,
                "type": "sell",
                "sub_type": null,
                "status": "final",
                "is_quotation": 0,
                "payment_status": "paid",
                "adjustment_type": null,
                "contact_id": 1,
                "customer_group_id": null,
                "invoice_no": "AS0007",
                "ref_no": "",
                "source": null,
                "subscription_no": null,
                "subscription_repeat_on": null,
                "transaction_date": "2020-06-04 23:29:36",
                "total_before_tax": "437.5000",
                "tax_id": 1,
                "tax_amount": "39.3750",
                "discount_type": "percentage",
                "discount_amount": "10.0000",
                "rp_redeemed": 0,
                "rp_redeemed_amount": "0.0000",
                "shipping_details": "Express Delivery",
                "shipping_address": null,
                "shipping_status": "ordered",
                "delivered_to": "Mr Robin",
                "shipping_charges": "10.0000",
                "additional_notes": null,
                "staff_note": null,
                "round_off_amount": "0.0000",
                "final_total": "453.1300",
                "expense_category_id": null,
                "expense_for": null,
                "commission_agent": null,
                "document": null,
                "is_direct_sale": 0,
                "is_suspend": 0,
                "exchange_rate": "1.000",
                "total_amount_recovered": null,
                "transfer_parent_id": null,
                "return_parent_id": null,
                "opening_stock_product_id": null,
                "created_by": 9,
                "import_batch": null,
                "import_time": null,
                "types_of_service_id": 1,
                "packing_charge": "10.0000",
                "packing_charge_type": "fixed",
                "service_custom_field_1": null,
                "service_custom_field_2": null,
                "service_custom_field_3": null,
                "service_custom_field_4": null,
                "mfg_parent_production_purchase_id": null,
                "mfg_wasted_units": null,
                "mfg_production_cost": "0.0000",
                "mfg_is_final": 0,
                "is_created_from_api": 0,
                "essentials_duration": "0.00",
                "essentials_duration_unit": null,
                "essentials_amount_per_unit_duration": "0.0000",
                "essentials_allowances": null,
                "essentials_deductions": null,
                "rp_earned": 0,
                "repair_completed_on": null,
                "repair_warranty_id": null,
                "repair_brand_id": null,
                "repair_status_id": null,
                "repair_model_id": null,
                "repair_defects": null,
                "repair_serial_no": null,
                "repair_updates_email": 0,
                "repair_updates_sms": 0,
                "repair_checklist": null,
                "repair_security_pwd": null,
                "repair_security_pattern": null,
                "repair_due_date": null,
                "repair_device_id": null,
                "order_addresses": null,
                "is_recurring": 0,
                "recur_interval": null,
                "recur_interval_type": "days",
                "recur_repetitions": 0,
                "recur_stopped_on": null,
                "recur_parent_id": null,
                "invoice_token": null,
                "pay_term_number": null,
                "pay_term_type": null,
                "pjt_project_id": null,
                "pjt_title": null,
                "woocommerce_order_id": null,
                "selling_price_group_id": 0,
                "created_at": "2020-06-04 23:29:36",
                "updated_at": "2020-06-04 23:29:36",
                "sell_lines": [
                    {
                        "id": 38,
                        "transaction_id": 55,
                        "product_id": 17,
                        "variation_id": 58,
                        "quantity": 1,
                        "mfg_waste_percent": "0.0000",
                        "quantity_returned": "0.0000",
                        "unit_price_before_discount": "437.5000",
                        "unit_price": "437.5000",
                        "line_discount_type": "fixed",
                        "line_discount_amount": "0.0000",
                        "unit_price_inc_tax": "437.5000",
                        "item_tax": "0.0000",
                        "tax_id": null,
                        "discount_id": null,
                        "lot_no_line_id": null,
                        "sell_line_note": "",
                        "res_service_staff_id": null,
                        "res_line_order_status": null,
                        "woocommerce_line_items_id": null,
                        "parent_sell_line_id": null,
                        "children_type": "",
                        "sub_unit_id": null,
                        "created_at": "2020-06-04 23:29:36",
                        "updated_at": "2020-06-04 23:29:36"
                    }
                ],
                "payment_lines": [
                    {
                        "id": 37,
                        "transaction_id": 55,
                        "business_id": 1,
                        "is_return": 0,
                        "amount": "453.1300",
                        "method": "cash",
                        "transaction_no": null,
                        "card_transaction_number": null,
                        "card_number": null,
                        "card_type": "credit",
                        "card_holder_name": null,
                        "card_month": null,
                        "card_year": null,
                        "card_security": null,
                        "cheque_number": null,
                        "bank_account_number": null,
                        "paid_on": "2020-06-04 23:29:36",
                        "created_by": 9,
                        "payment_for": 1,
                        "parent_id": null,
                        "note": null,
                        "document": null,
                        "payment_ref_no": "SP2020/0002",
                        "account_id": null,
                        "created_at": "2020-06-04 23:29:36",
                        "updated_at": "2020-06-04 23:29:36"
                    }
                ],

                "invoice_url": "http://local.pos.com/invoice/6dfd77eb80f4976b456128e7f1311c9f",
                "payment_link": "http://local.pos.com/pay/6dfd77eb80f4976b456128e7f1311c9f"
            }
        ]
    }
     */
    public function show($sell_ids)
    {
        $user = Auth::user();

        $business_id = $user->business_id;
        $sell_ids = explode(',', $sell_ids);

        $query = Transaction::where('business_id', $business_id)
                        ->whereIn('id', $sell_ids);

        $with = ['sell_lines', 'payment_lines'];

        if (! empty(request()->input('send_purchase_details')) && request()->input('send_purchase_details') == 1) {
            $with[] = 'sell_lines.sell_line_purchase_lines';
            $with[] = 'sell_lines.sell_line_purchase_lines.purchase_line';
        }

        $sells = $query->with($with)
                    ->get();

        return SellResource::collection($sells);
    }

    /**
     * Create sell
     *
     * @bodyParam sells.*.location_id int required id of the business location Example: 1
     * @bodyParam sells.*.contact_id int required id of the customer
     * @bodyParam sells.*.transaction_date string transaction date format:Y-m-d H:i:s, Example: 2020-07-22 15:48:29
     * @bodyParam sells.*.invoice_no string Invoice number
     * @bodyParam sells.*.source string Source of the invoice Example: api, phone, woocommerce
     * @bodyParam sells.*.status string sale status (final, draft) Example: final
     * @bodyParam sells.*.sub_status string sale sub status ("quotation" for quotation and "proforma" for proforma invoice) Example:null
     * @bodyParam sells.*.is_quotation boolean Is sell quotation (0, 1), If 1 status should be draft Example: 1
     * @bodyParam sells.*.tax_rate_id int id of the tax rate applicable to the sale
     * @bodyParam sells.*.discount_amount float discount amount applicable to the sale Example:10.00
     * @bodyParam sells.*.discount_type string  type of the discount amount (fixed, percentage) Example: fixed
     * @bodyParam sells.*.sale_note string
     * @bodyParam sells.*.staff_note string
     * @bodyParam sells.*.commission_agent int commission agent id
     * @bodyParam sells.*.shipping_details string shipping details Example: Express Delivery
     * @bodyParam sells.*.shipping_address string shipping address
     * @bodyParam sells.*.shipping_status string ('ordered', 'packed', 'shipped', 'delivered', 'cancelled') Example: ordered
     * @bodyParam sells.*.delivered_to string Name of the person recieved the consignment Example:'Mr robin'
     * @bodyParam sells.*.shipping_charges float shipping amount Example:10.0000
     * @bodyParam sells.*.packing_charge float packing charge Example:10
     * @bodyParam sells.*.exchange_rate float exchange rate for the currency used Example: 1
     * @bodyParam sells.*.selling_price_group_id int id of the selling price group
     * @bodyParam sells.*.pay_term_number int pay term value Example:3
     * @bodyParam sells.*.pay_term_type string type of the pay term value ('days', 'months') Example: months
     * @bodyParam sells.*.is_suspend boolean Is suspended sale (0, 1) Example: 0
     * @bodyParam sells.*.is_recurring int whether the invoice is recurring (0, 1) Example: 0
     * @bodyParam sells.*.recur_interval int value of the interval invoice will be regenerated
     * @bodyParam sells.*.recur_interval_type string type of the recur interval ('days', 'months', 'years') Example: months
     * @bodyParam sells.*.subscription_repeat_on int day of the month on which invoice will be generated if recur interval type is months (1-30) Example: 15
     * @bodyParam sells.*.subscription_no string subscription number
     * @bodyParam sells.*.recur_repetitions int total number of invoices to be generated
     * @bodyParam sells.*.rp_redeemed int reward points redeemed
     * @bodyParam sells.*.rp_redeemed_amount float reward point redeemed amount after conversion Example: 13.5000
     * @bodyParam sells.*.types_of_service_id int types of service id
     * @bodyParam sells.*.service_custom_field_1 string types of service custom field 1
     * @bodyParam sells.*.service_custom_field_2 string types of service custom field 2
     * @bodyParam sells.*.service_custom_field_3 string types of service custom field 3
     * @bodyParam sells.*.service_custom_field_4 string types of service custom field 4
     * @bodyParam sells.*.service_custom_field_5 string types of service custom field 5
     * @bodyParam sells.*.service_custom_field_6 string types of service custom field 6
     * @bodyParam sells.*.round_off_amount float round off amount on total payable
     * @bodyParam sells.*.table_id int id of the table
     * @bodyParam sells.*.service_staff_id int id of the service staff assigned to the sale
     * @bodyParam sells.*.change_return float Excess paid amount Example:0.0000
     * @bodyParam sells.*.products array required array of the products for the sale
     * @bodyParam sells.*.payments array payment lines for the sale
     *
     *
     * @bodyParam sells.*.products.*.product_id int required product id Example:17
     * @bodyParam sells.*.products.*.variation_id int required variation id Example:58
     * @bodyParam sells.*.products.*.quantity float required quantity Example: 1
     * @bodyParam sells.*.products.*.unit_price float unit selling price Example:437.5000
     * @bodyParam sells.*.products.*.tax_rate_id int tax rate id applicable on the product Example:null
     * @bodyParam sells.*.products.*.discount_amount float discount amount applicable on the product Example:0.0000
     * @bodyParam sells.*.products.*.discount_type string type of discount amount ('fixed', 'percentage') Example: percentage
     * @bodyParam sells.*.products.*.sub_unit_id int sub unit id
     * @bodyParam sells.*.products.*.res_service_staff_id int service staff id
     * @bodyParam sells.*.products.*.note string note for the product
     *
     *
     * @bodyParam sells.*.payments.*.amount float required amount of the payment Example: 453.1300
     * @bodyParam sells.*.payments.*.method string payment methods ('cash', 'card', 'cheque', 'bank_transfer', 'other', 'custom_pay_1', 'custom_pay_2', 'custom_pay_3') Example: cash
     * @bodyParam sells.*.payments.*.account_id int account id
     * @bodyParam sells.*.payments.*.card_number string
     * @bodyParam sells.*.payments.*.card_holder_name string
     * @bodyParam sells.*.payments.*.card_transaction_number string
     * @bodyParam sells.*.payments.*.card_type string
     * @bodyParam sells.*.payments.*.card_month string
     * @bodyParam sells.*.payments.*.card_year string
     * @bodyParam sells.*.payments.*.card_security string
     * @bodyParam sells.*.payments.*.transaction_no_1 string
     * @bodyParam sells.*.payments.*.transaction_no_2 string
     * @bodyParam sells.*.payments.*.transaction_no_3 string
     * @bodyParam sells.*.payments.*.bank_account_number string
     * @bodyParam sells.*.payments.*.note string payment note
     * @bodyParam sells.*.payments.*.cheque_number string
     *
     * @response {
        "data": [
            {
                "id": 6,
                "business_id": 1,
                "location_id": 1,
                "res_table_id": null,
                "res_waiter_id": null,
                "res_order_status": null,
                "type": "sell",
                "sub_type": null,
                "status": "final",
                "is_quotation": 0,
                "payment_status": "paid",
                "adjustment_type": null,
                "contact_id": 4,
                "customer_group_id": null,
                "invoice_no": "AS0001",
                "ref_no": "",
                "source": null,
                "subscription_no": null,
                "subscription_repeat_on": null,
                "transaction_date": "2018-04-10 13:23:21",
                "total_before_tax": "770.0000",
                "tax_id": null,
                "tax_amount": "0.0000",
                "discount_type": "percentage",
                "discount_amount": "0.0000",
                "rp_redeemed": 0,
                "rp_redeemed_amount": "0.0000",
                "shipping_details": null,
                "shipping_address": null,
                "shipping_status": null,
                "delivered_to": null,
                "shipping_charges": "0.0000",
                "additional_notes": null,
                "staff_note": null,
                "round_off_amount": "0.0000",
                "final_total": "770.0000",
                "expense_category_id": null,
                "expense_for": null,
                "commission_agent": null,
                "document": null,
                "is_direct_sale": 0,
                "is_suspend": 0,
                "exchange_rate": "1.000",
                "total_amount_recovered": null,
                "transfer_parent_id": null,
                "return_parent_id": null,
                "opening_stock_product_id": null,
                "created_by": 1,
                "import_batch": null,
                "import_time": null,
                "types_of_service_id": null,
                "packing_charge": null,
                "packing_charge_type": null,
                "service_custom_field_1": null,
                "service_custom_field_2": null,
                "service_custom_field_3": null,
                "service_custom_field_4": null,
                "mfg_parent_production_purchase_id": null,
                "mfg_wasted_units": null,
                "mfg_production_cost": "0.0000",
                "mfg_is_final": 0,
                "is_created_from_api": 0,
                "essentials_duration": "0.00",
                "essentials_duration_unit": null,
                "essentials_amount_per_unit_duration": "0.0000",
                "essentials_allowances": null,
                "essentials_deductions": null,
                "rp_earned": 0,
                "repair_completed_on": null,
                "repair_warranty_id": null,
                "repair_brand_id": null,
                "repair_status_id": null,
                "repair_model_id": null,
                "repair_defects": null,
                "repair_serial_no": null,
                "repair_updates_email": 0,
                "repair_updates_sms": 0,
                "repair_checklist": null,
                "repair_security_pwd": null,
                "repair_security_pattern": null,
                "repair_due_date": null,
                "repair_device_id": null,
                "order_addresses": null,
                "is_recurring": 0,
                "recur_interval": null,
                "recur_interval_type": null,
                "recur_repetitions": null,
                "recur_stopped_on": null,
                "recur_parent_id": null,
                "invoice_token": null,
                "pay_term_number": null,
                "pay_term_type": null,
                "pjt_project_id": null,
                "pjt_title": null,
                "woocommerce_order_id": null,
                "selling_price_group_id": null,
                "created_at": "2018-01-06 07:06:11",
                "updated_at": "2018-01-06 07:06:11",
                "invoice_url": "http://local.pos.com/invoice/6dfd77eb80f4976b456128e7f1311c9f",
                "payment_link": "http://local.pos.com/pay/6dfd77eb80f4976b456128e7f1311c9f",
                "sell_lines": [
                    {
                        "id": 1,
                        "transaction_id": 6,
                        "product_id": 2,
                        "variation_id": 3,
                        "quantity": 10,
                        "mfg_waste_percent": "0.0000",
                        "quantity_returned": "0.0000",
                        "unit_price_before_discount": "70.0000",
                        "unit_price": "70.0000",
                        "line_discount_type": null,
                        "line_discount_amount": "0.0000",
                        "unit_price_inc_tax": "77.0000",
                        "item_tax": "7.0000",
                        "tax_id": 1,
                        "discount_id": null,
                        "lot_no_line_id": null,
                        "sell_line_note": null,
                        "res_service_staff_id": null,
                        "res_line_order_status": null,
                        "woocommerce_line_items_id": null,
                        "parent_sell_line_id": null,
                        "children_type": "",
                        "sub_unit_id": null,
                        "created_at": "2018-01-06 07:06:11",
                        "updated_at": "2018-01-06 07:06:11"
                    }
                ],
                "payment_lines": [
                    {
                        "id": 1,
                        "transaction_id": 6,
                        "business_id": null,
                        "is_return": 0,
                        "amount": "770.0000",
                        "method": "cash",
                        "transaction_no": null,
                        "card_transaction_number": null,
                        "card_number": null,
                        "card_type": "visa",
                        "card_holder_name": null,
                        "card_month": null,
                        "card_year": null,
                        "card_security": null,
                        "cheque_number": null,
                        "bank_account_number": null,
                        "paid_on": "2018-01-09 17:30:35",
                        "created_by": 1,
                        "payment_for": null,
                        "parent_id": null,
                        "note": null,
                        "document": null,
                        "payment_ref_no": null,
                        "account_id": null,
                        "created_at": "2018-01-06 01:36:11",
                        "updated_at": "2018-01-06 01:36:11"
                    }
                ]
            }
        ]
    }
     */
    public function store(Request $request)
    {
        //TODO::Check customer credit limit
        try {
            $sells = $request->input('sells');
            $user = Auth::user();

            $business_id = $user->business_id;
            $business = Business::find($business_id);
            $commsn_agnt_setting = $business->sales_cmsn_agnt;
            $output = [];

            if (empty($sells) || ! is_array($sells)) {
                throw new \Exception('Invalid form data');
            }

            foreach ($sells as $sell_data) {
                try {
                    DB::beginTransaction();
                    $sell_data['business_id'] = $user->business_id;
                    $input = $this->__formatSellData($sell_data);

                    //TODO: temporarily used false to bypass the check, bcz of session issue in can_access_this_location function
                    //Check if location allowed
                    if (false && ! $user->can_access_this_location($input['location_id'])) {
                        throw new \Exception('User not allowed to access location with id '.$input['location_id']);
                    }

                    if (empty($input['products'])) {
                        throw new \Exception('No products added');
                    }

                    $discount = ['discount_type' => $input['discount_type'],
                        'discount_amount' => $input['discount_amount'],
                    ];
                    $invoice_total = $this->productUtil->calculateInvoiceTotal($input['products'], $input['tax_rate_id'], $discount, false);

                    if ($commsn_agnt_setting == 'logged_in_user') {
                        $input['commission_agent'] = $user->id;
                    }

                    $transaction = $this->transactionUtil->createSellTransaction($user->business_id, $input, $invoice_total, $user->id, false);

                    $this->transactionUtil->createOrUpdateSellLines($transaction, $input['products'], $input['location_id'], false, null, [], false);
                    //Add change return
                    $change_return = $this->dummyPaymentLine;
                    $change_return['amount'] = $input['change_return'];
                    $change_return['is_return'] = 1;
                    $input['payment'][] = $change_return;

                    if (! empty($input['payment']) && $transaction->is_suspend == 0) {
                        $this->transactionUtil->createOrUpdatePaymentLines($transaction, $input['payment'], $business_id, $user->id, false);
                    }

                    if ($input['status'] == 'final') {
                        //Check for final and do some processing.
                        //update product stock
                        foreach ($input['products'] as $product) {
                            $decrease_qty = $product['quantity'];
                            if (! empty($product['base_unit_multiplier'])) {
                                $decrease_qty = $decrease_qty * $product['base_unit_multiplier'];
                            }

                            if ($product['enable_stock']) {
                                $this->productUtil->decreaseProductQuantity(
                                    $product['product_id'],
                                    $product['variation_id'],
                                    $input['location_id'],
                                    $decrease_qty
                                );
                            }

                            if ($product['product_type'] == 'combo') {
                                //Decrease quantity of combo as well.
                                $this->productUtil
                                    ->decreaseProductQuantityCombo(
                                        $product['combo'],
                                        $input['location_id']
                                    );
                            }
                        }

                        //Update payment status
                        $this->transactionUtil->updatePaymentStatus($transaction->id, $transaction->final_total);

                        if ($business->enable_rp == 1) {
                            $redeemed = ! empty($input['rp_redeemed']) ? $input['rp_redeemed'] : 0;
                            $this->transactionUtil->updateCustomerRewardPoints($transaction->contact_id, $transaction->rp_earned, 0, $redeemed);
                        }

                        //Allocate the quantity from purchase and add mapping of
                        //purchase & sell lines in
                        //transaction_sell_lines_purchase_lines table
                        $business_details = $this->businessUtil->getDetails($business_id);
                        $pos_settings = empty($business_details->pos_settings) ? $this->businessUtil->defaultPosSettings() : json_decode($business_details->pos_settings, true);

                        $business_info = ['id' => $business_id,
                            'accounting_method' => $business->accounting_method,
                            'location_id' => $input['location_id'],
                            'pos_settings' => $pos_settings,
                        ];
                        $this->transactionUtil->mapPurchaseSell($business_info, $transaction->sell_lines, 'purchase');

                        //Auto send notification
                        $this->notificationUtil->autoSendNotification($business_id, 'new_sale', $transaction, $transaction->contact);

                        $client = $this->getClient();

                        $this->transactionUtil->activityLog($transaction, 'added', null, ['from_api' => $client]);
                    }

                    $transaction->invoice_url = $this->transactionUtil->getInvoiceUrl($transaction->id, $business_id);
                    $transaction->payment_link = $this->transactionUtil->getInvoicePaymentLink($transaction->id, $business_id);

                    DB::commit();
                    $output[] = $transaction;
                } catch (ModelNotFoundException $e) {
                    DB::rollback();

                    \Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());

                    $output[] = $this->modelNotFoundExceptionResult($e);
                } catch (\Exception $e) {
                    DB::rollback();

                    \Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());

                    $output[] = $this->otherExceptions($e);
                }
            }
        } catch (\Exception $e) {
            DB::rollback();

            \Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());

            $output[] = $this->otherExceptions($e);
        }

        return $output;
    }

    /**
     * Update sell
     *
     * @urlParam sell required id of sell to update Example: 6
     * @bodyParam contact_id int id of the customer
     * @bodyParam transaction_date string transaction date format:Y-m-d H:i:s, Example: 2020-5-7 15:20:22
     * @bodyParam status string sale status (final, draft) Example:final
     * @bodyParam sub_status string sale sub status ("quotation" for quotation and "proforma" for proforma invoice) Example:null
     * @bodyParam is_quotation boolean Is sell quotation (0, 1), If 1 status should be draft Example: 1
     * @bodyParam tax_rate_id int id of the tax rate applicable to the sale
     * @bodyParam discount_amount float discount amount applicable to the sale Example: 10.0000
     * @bodyParam discount_type string type of the discount amount (fixed, percentage) Example: fixed
     * @bodyParam sale_note string
     * @bodyParam source string Source of the invoice
     * @bodyParam staff_note string
     * @bodyParam is_suspend boolean Is suspended sale (0, 1) Example: 0
     * @bodyParam commission_agent int commission agent id
     * @bodyParam shipping_details string shipping details Example: Express Delivery
     * @bodyParam shipping_address string shipping address
     * @bodyParam shipping_status string ('ordered', 'packed', 'shipped', 'delivered', 'cancelled') Example:ordered
     * @bodyParam delivered_to string Name of the person recieved the consignment Example: Mr Robin
     * @bodyParam shipping_charges float shipping amount Example: 10.0000
     * @bodyParam packing_charge float packing charge Example: 10.0000
     * @bodyParam exchange_rate float exchange rate for the currency used Example:1
     * @bodyParam selling_price_group_id int id of the selling price group
     * @bodyParam pay_term_number int pay term value
     * @bodyParam pay_term_type string type of the pay term value ('days', 'months') Example: months
     * @bodyParam is_recurring int whether the invoice is recurring (0, 1) Example:0
     * @bodyParam recur_interval int value of the interval invoice will be regenerated
     * @bodyParam recur_interval_type string type of the recur interval ('days', 'months', 'years') Example:days
     * @bodyParam subscription_repeat_on int day of the month on which invoice will be generated if recur interval type is months (1-30) Example:7
     * @bodyParam subscription_no string subscription number
     * @bodyParam recur_repetitions int total number of invoices to be generated
     * @bodyParam rp_redeemed int reward points redeemed
     * @bodyParam rp_redeemed_amount float reward point redeemed amount after conversion Example: 13.5000
     * @bodyParam types_of_service_id int types of service id
     * @bodyParam service_custom_field_1 string types of service custom field 1
     * @bodyParam service_custom_field_2 string types of service custom field 2
     * @bodyParam service_custom_field_3 string types of service custom field 3
     * @bodyParam service_custom_field_4 string types of service custom field 4
     * @bodyParam service_custom_field_5 string types of service custom field 5
     * @bodyParam service_custom_field_6 string types of service custom field 6
     * @bodyParam round_off_amount float round off amount on total payable
     * @bodyParam table_id int id of the table
     * @bodyParam service_staff_id int id of the service staff assigned to the sale
     * @bodyParam change_return float Excess paid amount Example:0.0000
     * @bodyParam change_return_id int id of the change return payment if exists
     * @bodyParam products array required array of the products for the sale
     * @bodyParam payments array payment lines for the sale
     *
     *
     * @bodyParam products.*.sell_line_id int sell line id for existing item only
     * @bodyParam products.*.product_id int product id Example: 17
     * @bodyParam products.*.variation_id int variation id Example: 58
     * @bodyParam products.*.quantity float quantity Example: 1
     * @bodyParam products.*.unit_price float unit selling price Example: 437.5000
     * @bodyParam products.*.tax_rate_id int tax rate id applicable on the product
     * @bodyParam products.*.discount_amount float discount amount applicable on the product  Example:0.0000
     * @bodyParam products.*.discount_type string type of discount amount ('fixed', 'percentage') Example: percentage
     * @bodyParam products.*.sub_unit_id int sub unit id
     * @bodyParam products.*.res_service_staff_id int service staff id 
     * @bodyParam products.*.note string note for the product
     *
     *
     * @bodyParam payments.*.payment_id int payment id for existing payment line
     * @bodyParam payments.*.amount float amount of the payment Example:453.1300
     * @bodyParam payments.*.method string payment methods ('cash', 'card', 'cheque', 'bank_transfer', 'other', 'custom_pay_1', 'custom_pay_2', 'custom_pay_3') Example:cash
     * @bodyParam payments.*.account_id int account id
     * @bodyParam payments.*.card_number string
     * @bodyParam payments.*.card_holder_name string
     * @bodyParam payments.*.card_transaction_number string
     * @bodyParam payments.*.card_type string
     * @bodyParam payments.*.card_month string
     * @bodyParam payments.*.card_year string
     * @bodyParam payments.*.card_security string
     * @bodyParam payments.*.transaction_no_1 string
     * @bodyParam payments.*.transaction_no_2 string
     * @bodyParam payments.*.transaction_no_3 string
     * @bodyParam payments.*.note string payment note
     * @bodyParam payments.*.cheque_number string
     * @bodyParam payments.*.bank_account_number string
     *
     * @response {
        "id": 91,
        "business_id": 1,
        "location_id": 1,
        "res_table_id": null,
        "res_waiter_id": null,
        "res_order_status": null,
        "type": "sell",
        "sub_type": null,
        "status": "final",
        "is_quotation": 0,
        "payment_status": "paid",
        "adjustment_type": null,
        "contact_id": 1,
        "customer_group_id": 1,
        "invoice_no": "AS0020",
        "ref_no": "",
        "source": null,
        "subscription_no": null,
        "subscription_repeat_on": null,
        "transaction_date": "25-09-2020 15:22",
        "total_before_tax": 962.5,
        "tax_id": null,
        "tax_amount": 0,
        "discount_type": "fixed",
        "discount_amount": "19.5000",
        "rp_redeemed": 0,
        "rp_redeemed_amount": "0.0000",
        "shipping_details": null,
        "shipping_address": null,
        "shipping_status": null,
        "delivered_to": null,
        "shipping_charges": "0.0000",
        "additional_notes": null,
        "staff_note": null,
        "round_off_amount": "0.0000",
        "final_total": 943,
        "expense_category_id": null,
        "expense_for": null,
        "commission_agent": null,
        "document": null,
        "is_direct_sale": 0,
        "is_suspend": 0,
        "exchange_rate": "1.000",
        "total_amount_recovered": null,
        "transfer_parent_id": null,
        "return_parent_id": null,
        "opening_stock_product_id": null,
        "created_by": 9,
        "import_batch": null,
        "import_time": null,
        "types_of_service_id": null,
        "packing_charge": "0.0000",
        "packing_charge_type": null,
        "service_custom_field_1": null,
        "service_custom_field_2": null,
        "service_custom_field_3": null,
        "service_custom_field_4": null,
        "mfg_parent_production_purchase_id": null,
        "mfg_wasted_units": null,
        "mfg_production_cost": "0.0000",
        "mfg_production_cost_type": "percentage",
        "mfg_is_final": 0,
        "is_created_from_api": 0,
        "essentials_duration": "0.00",
        "essentials_duration_unit": null,
        "essentials_amount_per_unit_duration": "0.0000",
        "essentials_allowances": null,
        "essentials_deductions": null,
        "rp_earned": 0,
        "repair_completed_on": null,
        "repair_warranty_id": null,
        "repair_brand_id": null,
        "repair_status_id": null,
        "repair_model_id": null,
        "repair_job_sheet_id": null,
        "repair_defects": null,
        "repair_serial_no": null,
        "repair_checklist": null,
        "repair_security_pwd": null,
        "repair_security_pattern": null,
        "repair_due_date": null,
        "repair_device_id": null,
        "repair_updates_notif": 0,
        "order_addresses": null,
        "is_recurring": 0,
        "recur_interval": 1,
        "recur_interval_type": "days",
        "recur_repetitions": 0,
        "recur_stopped_on": null,
        "recur_parent_id": null,
        "invoice_token": null,
        "pay_term_number": null,
        "pay_term_type": null,
        "pjt_project_id": null,
        "pjt_title": null,
        "woocommerce_order_id": null,
        "selling_price_group_id": 0,
        "created_at": "2020-09-23 20:16:19",
        "updated_at": "2020-09-25 17:57:08",
        "payment_lines": [
            {
                "id": 55,
                "transaction_id": 91,
                "business_id": 1,
                "is_return": 0,
                "amount": "461.7500",
                "method": "cash",
                "transaction_no": null,
                "card_transaction_number": null,
                "card_number": null,
                "card_type": "credit",
                "card_holder_name": null,
                "card_month": null,
                "card_year": null,
                "card_security": null,
                "cheque_number": null,
                "bank_account_number": null,
                "paid_on": "2020-09-23 20:16:19",
                "created_by": 9,
                "is_advance": 0,
                "payment_for": 1,
                "parent_id": null,
                "note": null,
                "document": null,
                "payment_ref_no": "SP2020/0018",
                "account_id": null,
                "created_at": "2020-09-23 20:16:19",
                "updated_at": "2020-09-23 20:16:19"
            }
        ],
        "invoice_url": "http://local.pos.com/invoice/6dfd77eb80f4976b456128e7f1311c9f",
        "payment_link": "http://local.pos.com/pay/6dfd77eb80f4976b456128e7f1311c9f"
    }
     */
    public function update(Request $request, $id)
    {
        try {
            $user = Auth::user();

            $business_id = $user->business_id;
            $business = Business::find($business_id);

            $sell_data = $request->input();
            $sell_data['business_id'] = $user->business_id;

            $transaction_before = Transaction::where('business_id', $user->business_id)->with(['payment_lines'])
                                    ->findOrFail($id);

            //Check if location allowed
            if (! $user->can_access_this_location($transaction_before->location_id)) {
                throw new \Exception('User not allowed to access location with id '.$input['location_id']);
            }

            $status_before = $transaction_before->status;
            $rp_earned_before = $transaction_before->rp_earned;
            $rp_redeemed_before = $transaction_before->rp_redeemed;

            $sell_data['location_id'] = $transaction_before->location_id;
            $input = $this->__formatSellData($sell_data, $transaction_before);
            $discount = ['discount_type' => $input['discount_type'],
                'discount_amount' => $input['discount_amount'],
            ];
            $invoice_total = $this->productUtil->calculateInvoiceTotal($input['products'], $input['tax_rate_id'], $discount);

            //Begin transaction
            DB::beginTransaction();

            $transaction = $this->transactionUtil->updateSellTransaction($transaction_before, $business_id, $input, $invoice_total, $user->id, false);

            //Update Sell lines
            $deleted_lines = $this->transactionUtil->createOrUpdateSellLines($transaction, $input['products'], $input['location_id'], true, $status_before, [], false);
            if (! empty($input['payment']) && $transaction->is_suspend == 0) {
                $change_return = $this->dummyPaymentLine;
                $change_return['amount'] = $input['change_return'];
                $change_return['is_return'] = 1;
                if (! empty($input['change_return_id'])) {
                    $change_return['id'] = $input['change_return_id'];
                }
                $input['payment'][] = $change_return;

                $this->transactionUtil->createOrUpdatePaymentLines($transaction, $input['payment'], $business_id, $user->id, false);
            }

            if ($business->enable_rp == 1) {
                $this->transactionUtil->updateCustomerRewardPoints($transaction->contact_id, $transaction->rp_earned, $rp_earned_before, $transaction->rp_redeemed, $rp_redeemed_before);
            }

            //Update payment status
            $this->transactionUtil->updatePaymentStatus($transaction->id, $transaction->final_total);

            //Update product stock
            $this->productUtil->adjustProductStockForInvoice($status_before, $transaction, $input, false);

            //Allocate the quantity from purchase and add mapping of
            //purchase & sell lines in
            //transaction_sell_lines_purchase_lines table
            $business_details = $this->businessUtil->getDetails($business_id);
            $pos_settings = empty($business_details->pos_settings) ? $this->businessUtil->defaultPosSettings() : json_decode($business_details->pos_settings, true);

            $business = ['id' => $business_id,
                'accounting_method' => $business->accounting_method,
                'location_id' => $input['location_id'],
                'pos_settings' => $pos_settings,
            ];
            $this->transactionUtil->adjustMappingPurchaseSell($status_before, $transaction, $business, $deleted_lines);

            $updated_transaction = Transaction::where('business_id', $user->business_id)->with(['payment_lines'])
                                    ->findOrFail($id);

            $updated_transaction->invoice_url = $this->transactionUtil->getInvoiceUrl($updated_transaction->id, $business_id);
            $updated_transaction->payment_link = $this->transactionUtil->getInvoicePaymentLink($updated_transaction->id, $business_id);

            $output = $updated_transaction;

            $client = $this->getClient();

            $this->transactionUtil->activityLog($updated_transaction, 'edited', $transaction_before, ['from_api' => $client]);
            DB::commit();
        } catch (ModelNotFoundException $e) {
            DB::rollback();
            $output = $this->modelNotFoundExceptionResult($e);
        } catch (\Exception $e) {
            DB::rollback();

            \Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());

            $output = $this->otherExceptions($e);
        }

        return $output;
    }

    private function __getValue($key, $data, $obj, $default = null, $db_key = null)
    {
        $value = $default;

        if (isset($data[$key])) {
            $value = $data[$key];
        } elseif (! empty($obj)) {
            $key = ! empty($db_key) ? $db_key : $key;
            $value = $obj->$key;
        }

        return $value;
    }

    /**
     * Formats input form data to sell data
     *
     * @param  array  $data
     * @return array
     */
    private function __formatSellData($data, $transaction = null)
    {
        $business_id = $data['business_id'];
        $location = BusinessLocation::where('business_id', $business_id)
                                    ->findOrFail($data['location_id']);

        $customer_id = $this->__getValue('contact_id', $data, $transaction, null);
        $contact = Contact::where('business_id', $data['business_id'])
                            ->whereIn('type', ['customer', 'both'])
                            ->findOrFail($customer_id);

        $cg = $this->contactUtil->getCustomerGroup($business_id, $contact->id);
        $customer_group_id = (empty($cg) || empty($cg->id)) ? null : $cg->id;
        $formated_data = [
            'business_id' => $business_id,
            'location_id' => $location->id,
            'contact_id' => $contact->id,
            'customer_group_id' => $customer_group_id,
            'transaction_date' => $this->__getValue('transaction_date', $data,
                                $transaction, \Carbon::now()->toDateTimeString()),
            'invoice_no' => $this->__getValue('invoice_no', $data, $transaction, null, 'invoice_no'),
            'source' => $this->__getValue('source', $data, $transaction, null, 'source'),
            'status' => $this->__getValue('status', $data, $transaction, 'final'),
            'sub_status' => $this->__getValue('sub_status', $data, $transaction, null),
            'sale_note' => $this->__getValue('sale_note', $data, $transaction),
            'staff_note' => $this->__getValue('staff_note', $data, $transaction),
            'commission_agent' => $this->__getValue('commission_agent',
                                    $data, $transaction),
            'shipping_details' => $this->__getValue('shipping_details',
                                    $data, $transaction),
            'shipping_address' => $this->__getValue('shipping_address',
                                $data, $transaction),
            'shipping_status' => $this->__getValue('shipping_status', $data, $transaction),
            'delivered_to' => $this->__getValue('delivered_to', $data, $transaction),
            'shipping_charges' => $this->__getValue('shipping_charges', $data,
                $transaction, 0),
            'exchange_rate' => $this->__getValue('exchange_rate', $data, $transaction, 1),
            'selling_price_group_id' => $this->__getValue('selling_price_group_id', $data, $transaction),
            'pay_term_number' => $this->__getValue('pay_term_number', $data, $transaction),
            'pay_term_type' => $this->__getValue('pay_term_type', $data, $transaction),
            'is_recurring' => $this->__getValue('is_recurring', $data, $transaction, 0),
            'recur_interval' => $this->__getValue('recur_interval', $data, $transaction),
            'recur_interval_type' => $this->__getValue('recur_interval_type', $data, $transaction),
            'subscription_repeat_on' => $this->__getValue('subscription_repeat_on', $data, $transaction),
            'subscription_no' => $this->__getValue('subscription_no', $data, $transaction),
            'recur_repetitions' => $this->__getValue('recur_repetitions', $data, $transaction, 0),
            'order_addresses' => $this->__getValue('order_addresses', $data, $transaction),
            'rp_redeemed' => $this->__getValue('rp_redeemed', $data, $transaction, 0),
            'rp_redeemed_amount' => $this->__getValue('rp_redeemed_amount', $data, $transaction, 0),
            'is_created_from_api' => 1,
            'types_of_service_id' => $this->__getValue('types_of_service_id', $data, $transaction),
            'packing_charge' => $this->__getValue('packing_charge', $data, $transaction, 0),
            'packing_charge_type' => $this->__getValue('packing_charge_type', $data, $transaction),
            'service_custom_field_1' => $this->__getValue('service_custom_field_1', $data, $transaction),
            'service_custom_field_2' => $this->__getValue('service_custom_field_2', $data, $transaction),
            'service_custom_field_3' => $this->__getValue('service_custom_field_3', $data, $transaction),
            'service_custom_field_4' => $this->__getValue('service_custom_field_4', $data, $transaction),
            'service_custom_field_5' => $this->__getValue('service_custom_field_5', $data, $transaction),
            'service_custom_field_6' => $this->__getValue('service_custom_field_6', $data, $transaction),
            'round_off_amount' => $this->__getValue('round_off_amount', $data, $transaction),
            'res_table_id' => $this->__getValue('table_id', $data, $transaction, null, 'res_table_id'),
            'res_waiter_id' => $this->__getValue('service_staff_id', $data, $transaction, null, 'res_waiter_id'),
            'change_return' => $this->__getValue('change_return', $data, $transaction, 0),
            'change_return_id' => $this->__getValue('change_return_id', $data, $transaction, null),
            'is_quotation' => $this->__getValue('is_quotation', $data, $transaction, 0),
            'is_suspend' => $this->__getValue('is_suspend', $data, $transaction, 0),
        ];

        //Generate reference number
        if (! empty($formated_data['is_recurring'])) {
            //Update reference count
            $ref_count = $this->transactionUtil->setAndGetReferenceCount('subscription', $business_id);
            $formated_data['subscription_no'] = $this->transactionUtil->generateReferenceNumber('subscription', $ref_count, $business_id);
        }

        $sell_lines = [];
        $subtotal = 0;

        if (! empty($data['products'])) {
            foreach ($data['products'] as $product_data) {
                $sell_line = null;
                if (! empty($product_data['sell_line_id'])) {
                    $sell_line = TransactionSellLine::findOrFail($product_data['sell_line_id']);
                }

                $product_id = $this->__getValue('product_id', $product_data, $sell_line);
                $variation_id = $this->__getValue('variation_id', $product_data, $sell_line);
                $product = Product::where('business_id', $business_id)
                                ->with(['variations'])
                                ->findOrFail($product_id);

                $variation = $product->variations->where('id', $variation_id)->first();

                //Calculate line discount
                $unit_price = $this->__getValue('unit_price', $product_data, $sell_line, $variation->sell_price_inc_tax, 'unit_price_before_discount');

                $discount_amount = $this->__getValue('discount_amount', $product_data, $sell_line, 0, 'line_discount_amount');

                $line_discount = $discount_amount;
                $line_discount_type = $this->__getValue('discount_type', $product_data, $sell_line, 'fixed', 'line_discount_type');

                if ($line_discount_type == 'percentage') {
                    $line_discount = $this->transactionUtil->calc_percentage($unit_price, $discount_amount);
                }
                $discounted_price = $unit_price - $line_discount;

                //calculate line tax
                $item_tax = 0;
                $unit_price_inc_tax = $discounted_price;
                $tax_id = $this->__getValue('tax_rate_id', $product_data, $sell_line, null, 'tax_id');
                if (! empty($tax_id)) {
                    $tax = TaxRate::where('business_id', $business_id)
                                ->findOrFail($tax_id);

                    $item_tax = $this->transactionUtil->calc_percentage($discounted_price, $tax->amount);
                    $unit_price_inc_tax += $item_tax;
                }

                $formated_sell_line = [
                    'product_id' => $product->id,
                    'variation_id' => $variation->id,
                    'product_type' => $product->type,
                    'unit_price' => $unit_price,
                    'line_discount_type' => $line_discount_type,
                    'line_discount_amount' => $discount_amount,
                    'tax_id' => $tax_id,
                    'item_tax' => $item_tax,
                    'sell_line_note' => $this->__getValue('note', $product_data, $sell_line, null, 'sell_line_note'),
                    'enable_stock' => $product->enable_stock,
                    'quantity' => $this->__getValue('quantity', $product_data,
                                        $sell_line, 0),
                    'product_unit_id' => $product->unit_id,
                    'sub_unit_id' => $this->__getValue('sub_unit_id', $product_data,
                                        $sell_line),
                    'unit_price_inc_tax' => $unit_price_inc_tax,
                    'res_service_staff_id' => $this->__getValue('res_service_staff_id', $product_data,
                    $sell_line),
                ];
                if (! empty($sell_line)) {
                    $formated_sell_line['transaction_sell_lines_id'] = $sell_line->id;
                }

                if (($formated_sell_line['product_unit_id'] != $formated_sell_line['sub_unit_id']) && ! empty($formated_sell_line['sub_unit_id'])) {
                    $sub_unit = Unit::where('business_id', $business_id)
                                    ->findOrFail($formated_sell_line['sub_unit_id']);
                    $formated_sell_line['base_unit_multiplier'] = $sub_unit->base_unit_multiplier;
                } else {
                    $formated_sell_line['base_unit_multiplier'] = 1;
                }

                //Combo product
                if ($product->type == 'combo') {
                    $combo_variations = $this->productUtil->calculateComboDetails($location->id, $variation->combo_variations);
                    foreach ($combo_variations as $key => $value) {
                        $combo_variations[$key]['quantity'] = $combo_variations[$key]['qty_required'] * $formated_sell_line['quantity'] * $formated_sell_line['base_unit_multiplier'];
                    }

                    $formated_sell_line['combo'] = $combo_variations;
                }

                $line_total = $unit_price_inc_tax * $formated_sell_line['quantity'];

                $sell_lines[] = $formated_sell_line;

                $subtotal += $line_total;
            }
        }

        $formated_data['products'] = $sell_lines;

        //calculate sell discount and tax
        $order_discount_amount = $this->__getValue('discount_amount', $data, $transaction, 0);
        $order_discount_type = $this->__getValue('discount_type', $data, $transaction, 'fixed');
        $order_discount = $order_discount_amount;
        if ($order_discount_type == 'percentage') {
            $order_discount = $this->transactionUtil->calc_percentage($subtotal, $order_discount_amount);
        }
        $discounted_total = $subtotal - $order_discount;

        //calculate line tax
        $order_tax = 0;
        $final_total = $discounted_total;
        $order_tax_id = $this->__getValue('tax_rate_id', $data, $transaction);
        if (! empty($order_tax_id)) {
            $tax = TaxRate::where('business_id', $business_id)
                        ->findOrFail($order_tax_id);

            $order_tax = $this->transactionUtil->calc_percentage($discounted_total, $tax->amount);
            $final_total += $order_tax;
        }

        $formated_data['discount_amount'] = $order_discount_amount;
        $formated_data['discount_type'] = $order_discount_type;
        $formated_data['tax_rate_id'] = $order_tax_id;
        $formated_data['tax_calculation_amount'] = $order_tax;

        $final_total += $formated_data['shipping_charges'];

        if (! empty($formated_data['packing_charge']) && ! empty($formated_data['types_of_service_id'])) {
            $final_total += $formated_data['packing_charge'];
        }

        $formated_data['final_total'] = $final_total;

        $payments = [];
        if (! empty($data['payments'])) {
            foreach ($data['payments'] as $payment_data) {
                $transaction_payment = null;
                if (! empty($payment_data['payment_id'])) {
                    $transaction_payment = TransactionPayment::findOrFail($payment_data['payment_id']);
                }
                $payment = [
                    'amount' => $this->__getValue('amount', $payment_data, $transaction_payment),
                    'method' => $this->__getValue('method', $payment_data, $transaction_payment),
                    'account_id' => $this->__getValue('account_id', $payment_data, $transaction_payment),
                    'card_number' => $this->__getValue('card_number', $payment_data, $transaction_payment),
                    'card_holder_name' => $this->__getValue('card_holder_name', $payment_data, $transaction_payment),
                    'card_transaction_number' => $this->__getValue('card_transaction_number', $payment_data, $transaction_payment),
                    'card_type' => $this->__getValue('card_type', $payment_data, $transaction_payment),
                    'card_month' => $this->__getValue('card_month', $payment_data, $transaction_payment),
                    'card_year' => $this->__getValue('card_year', $payment_data, $transaction_payment),
                    'card_security' => $this->__getValue('card_security', $payment_data, $transaction_payment),
                    'cheque_number' => $this->__getValue('cheque_number', $payment_data, $transaction_payment),
                    'bank_account_number' => $this->__getValue('bank_account_number', $payment_data, $transaction_payment),
                    'transaction_no_1' => $this->__getValue('transaction_no_1', $payment_data, $transaction_payment),
                    'transaction_no_2' => $this->__getValue('transaction_no_2', $payment_data, $transaction_payment),
                    'transaction_no_3' => $this->__getValue('transaction_no_3', $payment_data, $transaction_payment),
                    'note' => $this->__getValue('note', $payment_data, $transaction_payment),
                ];
                if (! empty($transaction_payment)) {
                    $payment['payment_id'] = $transaction_payment->id;
                }

                $payments[] = $payment;
            }

            $formated_data['payment'] = $payments;
        }

        return $formated_data;
    }

    /**
     * Delete Sell
     *
     * @urlParam sell required id of the sell to be deleted
     */
    public function destroy($id)
    {
        try {
            $user = Auth::user();
            $business_id = $user->business_id;
            //Begin transaction
            DB::beginTransaction();

            $output = $this->transactionUtil->deleteSale($business_id, $id);

            DB::commit();
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());

            $output['success'] = false;
            $output['msg'] = trans('messages.something_went_wrong');
        }

        return $output;
    }

    /**
     * Update shipping status
     *
     * @bodyParam id int required id of the sale
     * @bodyParam shipping_status string ('ordered', 'packed', 'shipped', 'delivered', 'cancelled') Example:ordered
     * @bodyParam delivered_to string Name of the consignee
     */
    public function updateSellShippingStatus(Request $request)
    {
        try {
            $user = Auth::user();
            $business_id = $user->business_id;

            $sell_id = $request->input('id');
            $shipping_status = $request->input('shipping_status');
            $delivered_to = $request->input('delivered_to');
            $shipping_statuses = $this->transactionUtil->shipping_statuses();
            if (array_key_exists($shipping_status, $shipping_statuses)) {
                Transaction::where('business_id', $business_id)
                    ->where('id', $sell_id)
                    ->where('type', 'sell')
                    ->update(['shipping_status' => $shipping_status, 'delivered_to' => $delivered_to]);
            } else {
                return $this->otherExceptions('Invalid shipping status');
            }

            return $this->respond(['success' => 1,
                'msg' => trans('lang_v1.updated_success'),
            ]);
        } catch (\Exception $e) {
            \Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());

            return $this->otherExceptions($e);
        }
    }

    /**
     * Add Sell Return
     *
     * @bodyParam transaction_id integer required Id of the sell
     * @bodyParam transaction_date string transaction date format:Y-m-d H:i:s, Example: 2020-5-7 15:20:22
     * @bodyParam invoice_no string Invoice number of the return
     * @bodyParam discount_amount float discount amount applicable to the sale Example: 10.0000
     * @bodyParam discount_type string type of the discount amount (fixed, percentage) Example: fixed

     * @bodyParam products array required array of the products for the sale
     *
     * @bodyParam products.*.sell_line_id int required sell line id
     * @bodyParam products.*.quantity float required quantity to be returned from the sell line Example: 1
     * @bodyParam products.*.unit_price_inc_tax float required unit selling price of the returning item Example: 437.5000
     *
     * @response {
        "id": 159,
        "business_id": 1,
        "location_id": 1,
        "res_table_id": null,
        "res_waiter_id": null,
        "res_order_status": null,
        "type": "sell_return",
        "sub_type": null,
        "status": "final",
        "is_quotation": 0,
        "payment_status": "paid",
        "adjustment_type": null,
        "contact_id": 1,
        "customer_group_id": null,
        "invoice_no": "CN2020/0005",
        "ref_no": null,
        "subscription_no": null,
        "subscription_repeat_on": null,
        "transaction_date": "2020-11-17 00:00:00",
        "total_before_tax": 3,
        "tax_id": null,
        "tax_amount": 0,
        "discount_type": "percentage",
        "discount_amount": 12,
        "rp_redeemed": 0,
        "rp_redeemed_amount": "0.0000",
        "shipping_details": null,
        "shipping_address": null,
        "shipping_status": null,
        "delivered_to": null,
        "shipping_charges": "0.0000",
        "additional_notes": null,
        "staff_note": null,
        "round_off_amount": "0.0000",
        "final_total": 2.64,
        "expense_category_id": null,
        "expense_for": null,
        "commission_agent": null,
        "document": null,
        "is_direct_sale": 0,
        "is_suspend": 0,
        "exchange_rate": "1.000",
        "total_amount_recovered": null,
        "transfer_parent_id": null,
        "return_parent_id": 157,
        "opening_stock_product_id": null,
        "created_by": 9,
        "import_batch": null,
        "import_time": null,
        "types_of_service_id": null,
        "packing_charge": null,
        "packing_charge_type": null,
        "service_custom_field_1": null,
        "service_custom_field_2": null,
        "service_custom_field_3": null,
        "service_custom_field_4": null,
        "mfg_parent_production_purchase_id": null,
        "mfg_wasted_units": null,
        "mfg_production_cost": "0.0000",
        "mfg_production_cost_type": "percentage",
        "mfg_is_final": 0,
        "is_created_from_api": 0,
        "essentials_duration": "0.00",
        "essentials_duration_unit": null,
        "essentials_amount_per_unit_duration": "0.0000",
        "essentials_allowances": null,
        "essentials_deductions": null,
        "rp_earned": 0,
        "repair_completed_on": null,
        "repair_warranty_id": null,
        "repair_brand_id": null,
        "repair_status_id": null,
        "repair_model_id": null,
        "repair_job_sheet_id": null,
        "repair_defects": null,
        "repair_serial_no": null,
        "repair_checklist": null,
        "repair_security_pwd": null,
        "repair_security_pattern": null,
        "repair_due_date": null,
        "repair_device_id": null,
        "repair_updates_notif": 0,
        "order_addresses": null,
        "is_recurring": 0,
        "recur_interval": null,
        "recur_interval_type": null,
        "recur_repetitions": null,
        "recur_stopped_on": null,
        "recur_parent_id": null,
        "invoice_token": null,
        "pay_term_number": null,
        "pay_term_type": null,
        "pjt_project_id": null,
        "pjt_title": null,
        "woocommerce_order_id": null,
        "selling_price_group_id": null,
        "created_at": "2020-11-17 12:05:11",
        "updated_at": "2020-11-17 13:22:09"
    }
     */
    public function addSellReturn(Request $request)
    {
        try {
            $input = $request->except('_token');

            if (! empty($input['products'])) {
                $user = Auth::user();

                $business_id = $user->business_id;

                DB::beginTransaction();

                $output = $this->transactionUtil->addSellReturn($input, $business_id, $user->id);

                DB::commit();
            }
        } catch (ModelNotFoundException $e) {
            DB::rollback();
            $output = $this->modelNotFoundExceptionResult($e);
        } catch (\Exception $e) {
            DB::rollback();

            \Log::emergency('File:'.$e->getFile().'Line:'.$e->getLine().'Message:'.$e->getMessage());

            $output = $this->otherExceptions($e);
        }

        return $output;
    }

    /**
     * List Sell Return
     *
     * @urlParam sell_id Id of the sell for which return is added
     *
     * @response {
        "data": [
            {
                "id": 159,
                "business_id": 1,
                "location_id": 1,
                "res_table_id": null,
                "res_waiter_id": null,
                "res_order_status": null,
                "type": "sell_return",
                "sub_type": null,
                "status": "final",
                "is_quotation": 0,
                "payment_status": "partial",
                "adjustment_type": null,
                "contact_id": 1,
                "customer_group_id": null,
                "invoice_no": "CN2020/0005",
                "ref_no": null,
                "subscription_no": null,
                "subscription_repeat_on": null,
                "transaction_date": "2020-11-17 00:00:00",
                "total_before_tax": "3.0000",
                "tax_id": null,
                "tax_amount": "0.0000",
                "discount_type": "percentage",
                "discount_amount": "12.0000",
                "rp_redeemed": 0,
                "rp_redeemed_amount": "0.0000",
                "shipping_details": null,
                "shipping_address": null,
                "shipping_status": null,
                "delivered_to": null,
                "shipping_charges": "0.0000",
                "additional_notes": null,
                "staff_note": null,
                "round_off_amount": "0.0000",
                "final_total": "2.6400",
                "expense_category_id": null,
                "expense_for": null,
                "commission_agent": null,
                "document": null,
                "is_direct_sale": 0,
                "is_suspend": 0,
                "exchange_rate": "1.000",
                "total_amount_recovered": null,
                "transfer_parent_id": null,
                "return_parent_id": 157,
                "opening_stock_product_id": null,
                "created_by": 9,
                "import_batch": null,
                "import_time": null,
                "types_of_service_id": null,
                "packing_charge": null,
                "packing_charge_type": null,
                "service_custom_field_1": null,
                "service_custom_field_2": null,
                "service_custom_field_3": null,
                "service_custom_field_4": null,
                "mfg_parent_production_purchase_id": null,
                "mfg_wasted_units": null,
                "mfg_production_cost": "0.0000",
                "mfg_production_cost_type": "percentage",
                "mfg_is_final": 0,
                "is_created_from_api": 0,
                "essentials_duration": "0.00",
                "essentials_duration_unit": null,
                "essentials_amount_per_unit_duration": "0.0000",
                "essentials_allowances": null,
                "essentials_deductions": null,
                "rp_earned": 0,
                "repair_completed_on": null,
                "repair_warranty_id": null,
                "repair_brand_id": null,
                "repair_status_id": null,
                "repair_model_id": null,
                "repair_job_sheet_id": null,
                "repair_defects": null,
                "repair_serial_no": null,
                "repair_checklist": null,
                "repair_security_pwd": null,
                "repair_security_pattern": null,
                "repair_due_date": null,
                "repair_device_id": null,
                "repair_updates_notif": 0,
                "order_addresses": null,
                "is_recurring": 0,
                "recur_interval": null,
                "recur_interval_type": null,
                "recur_repetitions": null,
                "recur_stopped_on": null,
                "recur_parent_id": null,
                "invoice_token": null,
                "pay_term_number": null,
                "pay_term_type": null,
                "pjt_project_id": null,
                "pjt_title": null,
                "woocommerce_order_id": null,
                "selling_price_group_id": null,
                "created_at": "2020-11-17 12:05:11",
                "updated_at": "2020-11-17 13:22:09",
                "payment_lines": [
                    {
                        "id": 126,
                        "transaction_id": 159,
                        "business_id": 1,
                        "is_return": 0,
                        "amount": "1.8000",
                        "method": "cash",
                        "transaction_no": null,
                        "card_transaction_number": null,
                        "card_number": null,
                        "card_type": "credit",
                        "card_holder_name": null,
                        "card_month": null,
                        "card_year": null,
                        "card_security": null,
                        "cheque_number": null,
                        "bank_account_number": null,
                        "paid_on": "2020-11-17 12:05:00",
                        "created_by": 9,
                        "is_advance": 0,
                        "payment_for": 1,
                        "parent_id": null,
                        "note": null,
                        "document": null,
                        "payment_ref_no": "SP2020/0078",
                        "account_id": null,
                        "created_at": "2020-11-17 12:05:58",
                        "updated_at": "2020-11-17 12:05:58"
                    }
                ],
                "return_parent_sell": {
                    "id": 157,
                    "business_id": 1,
                    "location_id": 1,
                    "res_table_id": null,
                    "res_waiter_id": null,
                    "res_order_status": null,
                    "type": "sell",
                    "sub_type": null,
                    "status": "final",
                    "is_quotation": 0,
                    "payment_status": "paid",
                    "adjustment_type": null,
                    "contact_id": 1,
                    "customer_group_id": null,
                    "invoice_no": "AS0073",
                    "ref_no": "",
                    "subscription_no": null,
                    "subscription_repeat_on": null,
                    "transaction_date": "2020-11-13 12:42:17",
                    "total_before_tax": "6.2500",
                    "tax_id": null,
                    "tax_amount": "0.0000",
                    "discount_type": "percentage",
                    "discount_amount": "10.0000",
                    "rp_redeemed": 0,
                    "rp_redeemed_amount": "0.0000",
                    "shipping_details": null,
                    "shipping_address": null,
                    "shipping_status": null,
                    "delivered_to": null,
                    "shipping_charges": "0.0000",
                    "additional_notes": null,
                    "staff_note": null,
                    "round_off_amount": "0.0000",
                    "final_total": "5.6300",
                    "expense_category_id": null,
                    "expense_for": null,
                    "commission_agent": null,
                    "document": null,
                    "is_direct_sale": 0,
                    "is_suspend": 0,
                    "exchange_rate": "1.000",
                    "total_amount_recovered": null,
                    "transfer_parent_id": null,
                    "return_parent_id": null,
                    "opening_stock_product_id": null,
                    "created_by": 9,
                    "import_batch": null,
                    "import_time": null,
                    "types_of_service_id": null,
                    "packing_charge": "0.0000",
                    "packing_charge_type": null,
                    "service_custom_field_1": null,
                    "service_custom_field_2": null,
                    "service_custom_field_3": null,
                    "service_custom_field_4": null,
                    "mfg_parent_production_purchase_id": null,
                    "mfg_wasted_units": null,
                    "mfg_production_cost": "0.0000",
                    "mfg_production_cost_type": "percentage",
                    "mfg_is_final": 0,
                    "is_created_from_api": 0,
                    "essentials_duration": "0.00",
                    "essentials_duration_unit": null,
                    "essentials_amount_per_unit_duration": "0.0000",
                    "essentials_allowances": null,
                    "essentials_deductions": null,
                    "rp_earned": 0,
                    "repair_completed_on": null,
                    "repair_warranty_id": null,
                    "repair_brand_id": null,
                    "repair_status_id": null,
                    "repair_model_id": null,
                    "repair_job_sheet_id": null,
                    "repair_defects": null,
                    "repair_serial_no": null,
                    "repair_checklist": null,
                    "repair_security_pwd": null,
                    "repair_security_pattern": null,
                    "repair_due_date": null,
                    "repair_device_id": null,
                    "repair_updates_notif": 0,
                    "order_addresses": null,
                    "is_recurring": 0,
                    "recur_interval": 1,
                    "recur_interval_type": "days",
                    "recur_repetitions": 0,
                    "recur_stopped_on": null,
                    "recur_parent_id": null,
                    "invoice_token": null,
                    "pay_term_number": null,
                    "pay_term_type": null,
                    "pjt_project_id": null,
                    "pjt_title": null,
                    "woocommerce_order_id": null,
                    "selling_price_group_id": 0,
                    "created_at": "2020-11-13 12:42:17",
                    "updated_at": "2020-11-13 12:42:18",
                    "sell_lines": [
                        {
                            "id": 139,
                            "transaction_id": 157,
                            "product_id": 157,
                            "variation_id": 205,
                            "quantity": 5,
                            "mfg_waste_percent": "0.0000",
                            "quantity_returned": "3.0000",
                            "unit_price_before_discount": "1.2500",
                            "unit_price": "1.2500",
                            "line_discount_type": "fixed",
                            "line_discount_amount": "0.0000",
                            "unit_price_inc_tax": "1.2500",
                            "item_tax": "0.0000",
                            "tax_id": null,
                            "discount_id": null,
                            "lot_no_line_id": null,
                            "sell_line_note": "",
                            "res_service_staff_id": null,
                            "res_line_order_status": null,
                            "woocommerce_line_items_id": null,
                            "parent_sell_line_id": null,
                            "children_type": "",
                            "sub_unit_id": null,
                            "created_at": "2020-11-13 12:42:17",
                            "updated_at": "2020-11-17 13:22:09"
                        }
                    ]
                }
            }
        ],
        "links": {
            "first": "http://local.pos.com/connector/api/list-sell-return?sell_id=157&page=1",
            "last": null,
            "prev": null,
            "next": null
        },
        "meta": {
            "current_page": 1,
            "from": 1,
            "path": "http://local.pos.com/connector/api/list-sell-return",
            "per_page": 10,
            "to": 1
        }
    }
     */
    public function listSellReturn()
    {
        $filters = request()->input();
        $user = Auth::user();
        $business_id = $user->business_id;

        $sell_id = request()->input('sell_id');
        $query = Transaction::where('business_id', $business_id)
                            ->where('type', 'sell_return')
                            ->where('status', 'final')
                            ->with(['payment_lines', 'return_parent_sell', 'return_parent_sell.sell_lines'])
                            ->select('transactions.*');

        $permitted_locations = $user->permitted_locations();
        if ($permitted_locations != 'all') {
            $query->whereIn('transactions.location_id', $permitted_locations);
        }

        if (! empty($sell_id)) {
            $query->where('return_parent_id', $sell_id);
        }

        $perPage = ! empty($filters['per_page']) ? $filters['per_page'] : $this->perPage;
        if ($perPage == -1) {
            $sell_returns = $query->get();
        } else {
            $sell_returns = $query->paginate($perPage);
            $sell_returns->appends(request()->query());
        }

        return SellResource::collection($sell_returns);
    }
}