File "Order.php"

Full Path: /home/clickysoft/public_html/jmapi5.clickysoft.net/app/Models/Order.php
File size: 34.15 KB
MIME-type: text/x-php
Charset: utf-8

<?php

namespace App\Models;

use App\Http\Controllers\Traits\MediaUploadingTrait;
use App\Http\Resources\Admin\OrderInfoResource;
use App\Notifications\OrderApprovedConfirmedNotification;
use App\Notifications\OrderArtworkReminderNotification;
use App\Notifications\OrderCompletedNotification;
use App\Notifications\OrderPickedShippedNotification;
use Barryvdh\DomPDF\Facade\Pdf;
use \DateTimeInterface;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

class Order extends Model
{
    use HasFactory, MediaUploadingTrait;

    protected $guarded = ['_token'];

    public const PAYMENT_STATUS_RADIO = [
        'Unpaid' => 'Unpaid',
        'Paid'   => 'Paid',
    ];

    public const PAYMENT_MODE_RADIO = [
        'Partial',
        'Full',
    ];

    public const PAYMENT_TYPE_RADIO = [
        'Cash'                  => 'Cash',
        'Credit Card'           => 'Credit Card',
        'Purchase Order'        => 'Purchase Order',
        'Check'                 => 'Check',
        'PayJunction Invoice'   => 'PayJunction Invoice',
        'None'                  => 'None',
    ];

    public const ORDER_TYPE_RADIO = [
        'Order' => 'Order',
        'Quote' => 'Quote',
    ];

    public const RUSH_ORDER_RADIO = [
        'Same Day' => 'Same Day',
        'Rush Order 48' => 'Rush Order 48',
        'Rush Order 72' => 'Rush Order 72',
    ];

    public const ADMIN_APPROVED = [
        'No',
        'Yes',
    ];

    public const WAIVE_OFF_OPTIONS = [
        "Federal Government",
        "Reseller Exemption",
        "Out of tax nexus",
        "Non-Profit Organization",
    ];

    public const DELIVERY_TYPE = [
        'Shipping' => 'Shipping',
        'Pickup' => 'Pickup',
    ];

    public const DELIVERY_PACKAGES = [
        'ups_next_day_air' => 'Overnight (1 Day)',
        'ups_second_day_air' => '2nd Day Air (2 Days)',
        'ups_three_day_select' => 'Priority Shipping',
        'ups_ground' => 'Ground Shipping (5-7 days)',
    ];

    public const REPORTS_MODE = [
        'previous_month' => 'previousMonth',
        'current_month' => 'currentMonth',
        'previous_year' => 'previousYear',
        'current_year' => 'currentYear',
        'all' => 'untilToday',
    ];

    public $table = 'orders';

    protected $dates = [
        'created_at',
        'updated_at',
        'deleted_at',
    ];

    protected $casts = [
        'payment_date' => 'datetime',
        'delivery_date' => 'date',
        'event_date' => 'date',
        'date_scheduled' => 'date',
        'date_pick_or_ship_by' => 'date',
    ];

    public const ADMIN_ORDER_STATUS_ALLOWED = [
        1 => [2 => "Order Acknowledgement", 10 => "Order Cancelled"],
        2 => [
            3 => "Product Ordered/In Stock",
            4 => "Artwork Received",
            6 => "Proof sent to customer",
            8 => "Waiting on customer",
            9 => "Proof sign off received",
            10 => "Order Cancelled",
        ],
        3 => [
            5 => "Products Received/Shelved",
            10 => "Order Cancelled",
        ],
        4 => [10 => "Order Cancelled", 11 => "In Production"],
        5 => [
            10 => "Order Cancelled",
            11 => "In Production",
        ],
        6 => [8 => "Waiting on customer", 9 => "Proof sign off received",],
        7 => [10 => "Order Cancelled", 11 => "In Production"],
        8 => [9 => "Proof sign off received",],
        9 => [
            10 => "Order Cancelled",
            11 => "In Production",
        ],
        10 => [],
        11 => [12 => "In Assembly/Cleaning"],
        12 => [13 => "Complete/Customer Notified"]
    ];

    protected function getPurchaseOrderCopyUrlAttribute()
    {
        return $this->purchase_order_copy
            ? asset('storage/order/' . $this->purchase_order_copy)
            : $this->purchase_order_copy;
    }

    public function user()
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    public function current_status()
    {
        return $this->belongsTo(Status::class, 'current_status_id');
    }

    public function assigned_to()
    {
        return $this->belongsTo(User::class, 'assigned_to_id');
    }

    public function shipping_address()
    {
        return $this->belongsTo(AddressBook::class, 'shipping_address_id');
    }

    public function billing_address()
    {
        return $this->belongsTo(AddressBook::class, 'billing_address_id');
    }

    protected function serializeDate(DateTimeInterface $date)
    {
        return $date->format('Y-m-d H:i:s');
    }

    protected function getAdminApprovedStatusAttribute()
    {
        return self::ADMIN_APPROVED[$this->admin_approved];
    }

    protected function getFormatedPaymentDateAttribute()
    {
        return $this->payment_date == null ? null : $this->payment_date->format('m-d-Y h:i:s');
    }

    public function statuses()
    {
        return $this->belongsToMany(Status::class, 'order_status')->withPivot('notes', 'created_at', 'updated_at', 'user_id');
    }

    public function items()
    {
        return $this->hasMany(OrderItems::class, 'order_id');
    }

    public function itemVariations()
    {
        return $this->hasMany(OrderItemVariation::class, 'order_id');
    }

    public function purchaseOrder()
    {
        return $this->belongsTo(PurchaseOrderToCreate::class, 'order_id');
    }

    public function notes()
    {
        return $this->hasMany(OrderNotes::class, 'order_id');
    }

    public function pickLocation()
    {
        return $this->belongsTo(StoreLocation::class, 'pickup_location_id');
    }

    public function getOrderAddress($address_id, $prefix)
    {
        $address = AddressBook::find($address_id);

        if (!$address) return [];

        return [
            $prefix . '_company_name' => $address->company_name,
            $prefix . '_primary_contact_name' => $address->primary_contact_name,
            $prefix . '_primary_contact_email' => $address->primary_contact_email,
            $prefix . '_secondary_contact_name' => $address->secondary_contact_name,
            $prefix . '_secondary_contact_email' => $address->secondary_contact_email,
            $prefix . '_address_line_1' => $address->address_line_1,
            $prefix . '_address_line_2' => $address->address_line_2,
            $prefix . '_city' => $address->city,
            $prefix . '_state' => $address->state?->name,
            $prefix . '_zipcode' => $address->zipcode,
            $prefix . '_phone_number' => $address->phone_number,
        ];
    }

    public function str_random($number)
    {
        return str_pad($number, 3, 0, STR_PAD_LEFT);
    }

    public function str_random2()
    {
        $order = Order::orderBy('id', 'desc')->first();
        if (!$order) return 1000;
        return ($order->id) + 1000;
    }

    public function storeOrderProducts($products, $user_id, $is_add_request = false): array
    {
        $variation_ids = $item_ids = $return_data = [];

        foreach ($products as $product) {
            $existing_order_item_clone = null;
            $price = ProductPrice::where(['id' => $product['price_id'], 'product_id' => $product['product_id']])->first();

            //Get the new or existing pricing order item
            if (isset($product['item_id']) && $product['item_id'] != null) {
                $existing_order_item = OrderItems::find($product['item_id']);
                $accountable_price = $existing_order_item->price;
                $accountable_engraving_fee = $existing_order_item->engraving_fee;
            } else {
                $db_product = Product::find($product['product_id']);
                $price_range = ProductVariationRange::where('product_price_id', $price->id)
                    ->where('qty_from', '<=', $product['quantity'])
                    ->where('qty_to', '>=', $product['quantity'])
                    ->first();
                $accountable_price = $price_range->price;
                $accountable_engraving_fee = $db_product->engraving_fee;
            }

            $prodData = [
                'product_id' => $product['product_id'],
                'price_id' => $product['price_id'],
                'notes' => $product['notes'] ?? '',
                'sketch_file' => $product['sketch_file'] ?? null,
                'customization' => $product['product_customization'] ?? '[]',
            ];

            if (isset($product['item_id']) && $product['item_id'] != null) {

                //Add another entry with difference if quantity has increased.
                if ($product['quantity'] > $existing_order_item->quantity) {
                    $existing_order_item_clone = $existing_order_item->replicate();
                    $existing_order_item_clone->quantity = $product['quantity'] - $existing_order_item->quantity;
                    $existing_order_item_clone->engraving_fee_total = $existing_order_item_clone->quantity * $existing_order_item_clone->engraving_fee;
                    $existing_order_item_clone->total_price = ($existing_order_item_clone->quantity * $existing_order_item_clone->price) + $existing_order_item_clone->engraving_fee_total;
                    $existing_order_item_clone->po_created = false;
                    $existing_order_item_clone->created_at = new \DateTime();
                    $existing_order_item_clone->updated_at = new \DateTime();
                    $existing_order_item_clone->save();
                    $item_ids[] = $existing_order_item_clone->id;
                } else {
                    $existing_order_item->update(
                        array_merge($prodData, [
                            'quantity' => $product['quantity'],
                            'total_price' => $accountable_price * $product['quantity'],
                        ])
                    );
                    $existing_order_item->save();
                }
            } else {
                $existing_order_item = OrderItems::create(
                    array_merge($prodData, [
                        'quantity' => $product['quantity'],
                        'order_id' => $this->id,
                        'total_price' => $accountable_price * $product['quantity'],
                        'qty_from' => $price_range->qty_from,
                        'qty_to' => $price_range->qty_to,
                        'price' => $accountable_price,
                    ])
                );
            }

            if (isset($product['approve_consent'])) {
                $existing_order_item->approve_consent = $product['approve_consent'];
            }

            $template = "";

            if (isset($product['template'])) {
                $template = $this->storePDF($product['template'], $user_id, 'order');
            }

            //Check for Artwork Received Status
            if (isset($product['template']) || isset($product['product_customization'])) {
                if (!isset($return_data['artwork_check'])) {
                    $return_data['artwork_check'] = 1;
                }
                $existing_order_item->engraving_fee = $accountable_engraving_fee;
                $existing_order_item->engraving_fee_total = $accountable_engraving_fee * $existing_order_item->quantity;
                $existing_order_item->total_price_after_engraving = $existing_order_item->total_price + $existing_order_item->engraving_fee_total;
            } else {
                $existing_order_item->total_price_after_engraving = $existing_order_item->total_price + $existing_order_item->engraving_fee_total;
            }
            $existing_order_item->save();

            if ($template != "") {
                $existing_order_item->template = $template ?? $existing_order_item->template;

                //Create PNG from pdf template
                pdfToImages($user_id, $existing_order_item->id, $existing_order_item->template);
            }
            $existing_order_item->image = $image ?? $existing_order_item->image;
            $existing_order_item->product_name = $existing_order_item->product?->name;
            $existing_order_item->save();
            $item_ids[] = $existing_order_item->id;
            //Store Order Item Combination
            foreach ($price->combinations ?? [] as $com) {
                $v = OrderItemVariation::updateOrCreate([
                    'order_id' => $this->id,
                    'product_id' => $product['product_id'],
                    'order_item_id' => $existing_order_item->id,
                    'variation_id' => $com->variation_id,
                ], [
                    'order_id' => $this->id,
                    'product_id' => $product['product_id'],
                    'order_item_id' => $existing_order_item->id,
                    'variation_id' => $com->variation_id,
                ]);

                if ($existing_order_item_clone) {
                    $v_clone = $v->replicate();
                    $v_clone->order_item_id = $existing_order_item_clone->id;
                    $v_clone->save();
                    $variation_ids[] = $v_clone->id;
                }

                $variation_ids[] = $v->id;
            }
        }

        if (!$is_add_request) {
            $this->itemVariations()->whereNotIn('id', $variation_ids)->delete();
            $this->items()->whereNotIn('id', $item_ids)->delete();
        }

        $this->save();
        return $return_data;
    }

    public function createPurchaseOrderItem()
    {
        $items_not_to_delete = [];
        foreach ($this->items as $item) {
            if (!$item->po_created) {
                $po_to_create_item = PurchaseOrderToCreate::updateOrCreate(
                    [
                        'order_item_id' => $item->id,
                    ],
                    [
                        'order_id' => $this->id,
                        'order_item_id' => $item->id,
                        'product_id' => $item->product_id,
                        'price_id' => $item->price_id,
                        'quantity' => $item->quantity,
                    ]
                );
                $items_not_to_delete[] = $po_to_create_item->id;
            }
        }
        PurchaseOrderToCreate::where('order_id', $this->id)->whereNotIn('id', $items_not_to_delete)->delete();
    }

    public function deletePurchaseOrderItem()
    {
        PurchaseOrderToCreate::where('order_id', $this->id)->delete();
    }

    public function stockLocation(): BelongsTo
    {
        return $this->belongsTo(StockLocation::class, 'stock_location_id');
    }

    public function invoice(): BelongsTo
    {
        return $this->belongsTo(OrderInvoice::class, 'invoice_id');
    }

    public function payment(): BelongsTo
    {
        return $this->belongsTo(PayJunctionPayments::class, 'payment_id');
    }

    public function createInvoice()
    {
        $payment_url = $pj_invoice_url = null;
        if ($this->payment_status == "Unpaid") {
            $payment_url = config('app.react_app_payment_url') . $this->id;
            $pj_invoice_url = generatePJInvoice($this);
        }

        //Business Information
        $site_email = SiteSetting::where('key', 'Site Email')->first();
        $site_phone = SiteSetting::where('key', 'Site Phone')->first();
        $location_1 = SiteSetting::where('key', 'Location')->first();
        $location_2 = SiteSetting::where('key', 'Location 2')->first();
        $user_id = $this->user_id;
        $pdf = PDF::loadView('partials.invoice', [
            'payment_url' => $payment_url,
            'pj_invoice_url' => $pj_invoice_url->hostedInvoiceUrl ?? null,
            'invoice_number' => $this->order_number,
            'invoice_date' => now(),
            'order' => new OrderInfoResource($this),
            'customer' => $this->user,
            'orderDetails' => $this->items,
            'site_email' => $site_email->value ?? "NA",
            'site_phone' => $site_phone->value ?? "NA",
            'location_1' => $location_1->value ?? "NA",
            'location_2' => $location_2->value ?? "NA",
        ])->setPaper('A4')->setOption([
            'fontDir' => public_path(),
        ]);

        $pdf_name = $this->order_number . '.pdf';
        $file_path = public_path('storage/order/' . $user_id . '/' . $pdf_name);
        if (!Storage::disk('order')->exists($user_id)) {
            Storage::disk('order')->makeDirectory($user_id);
        }

        $pdf->save($file_path);

        $invoice = OrderInvoice::updateOrCreate([
            'invoice_number' => $this->order_number,
        ], [
            'order_id' => $this->id,
            'invoice_number' => $this->order_number,
            'pdf' => $this->user_id . '/' . $this->order_number . '.pdf',
        ]);

        $this->invoice_id = $invoice->id;
        $this->save();

        return $invoice;
    }

    public function getAllowedStatus()
    {
        return isset(Order::ADMIN_ORDER_STATUS_ALLOWED[$this->current_status_id])
            ? Order::ADMIN_ORDER_STATUS_ALLOWED[$this->current_status_id]
            : [];
    }

    public function getOrderTotals(Request $request, $order = null): array
    {
        //Calculate Product totals

        $data = $discount = [];
        $product_total = $shipping_amount = $engraving_fee = $rush_order_fee = $order_total = 0;
        $engraving_fee_of_all_products = 0;
        foreach ($request->products as $product) {
            $p_engraving = 0;
            if (isset($product['item_id']) && $product['item_id'] != null) {
                $existing_order_item = OrderItems::find($product['item_id']);
                $accountable_price = $existing_order_item->price;
                $accountable_engraving_fee = $existing_order_item->engraving_fee;
            } else {
                $db_product = Product::find($product['product_id']);
                $db_product_price = ProductPrice::find($product['price_id']);
                $price_range = ProductVariationRange::where('product_price_id', $db_product_price->id)
                    ->where('qty_from', '<=', $product['quantity'])
                    ->where('qty_to', '>=', $product['quantity'])
                    ->first();
                $accountable_price = $price_range->price;
                $accountable_engraving_fee = $db_product->engraving_fee;
            }
            $product_total += $accountable_price * $product['quantity'];
            $p_total = $accountable_price * $product['quantity'];
            if (isset($product['template']) || isset($product['customization']) || isset($product['product_customization'])) {
                $engraving_fee += $accountable_engraving_fee * $product['quantity'];
                $p_engraving = $accountable_engraving_fee * $product['quantity'];
            } else if (isset($product['include_engraving_fee']) && $product['include_engraving_fee']) {
                $engraving_fee += $accountable_engraving_fee * $product['quantity'];
                $p_engraving = $accountable_engraving_fee * $product['quantity'];
            }
            $data['products'][] = [
                'product_id' => $product['product_id'],
                'price_id' => $product['price_id'],
                'engraving_fee' => $p_engraving,
                'total' => $p_total,
                'total_with_engraving' => $p_total + $p_engraving,
            ];
        }
        $product_total += $engraving_fee;
        $engraving_fee_of_all_products += $engraving_fee;
        $data['items_total'] = $product_total;

        if ($request['delivery_type'] == 'Shipping') {

            if ($request->has("third_party_shipping")) {
                $shipping_amount = (float)$request->get("shipping_total_amount");
            } else {
                $customer_id = config('app.web_ship_customer_id');
                $base_url = config('app.web_ship_base_url');
                $endpoint = "{$base_url}/customers/{$customer_id}/quote";

                $request_body = prepareDataForShippingQuote($request);
                $response = getShippingQuoteServices($request_body, $endpoint);
                if ($response['data']) {
                    $shipping_amount = $response['data']['totalAmount'];
                }
            }
        }

        $billingAddress = AddressBook::find($request['billing_address_id']);
        $state = StateSalesTax::find($billingAddress->state_id);
        $state_sales_tax = $state->tax_percentage ?? 0;

        $data['rush_order'] = [
            'type' => null,
            'percentage' => 0.00,
        ];

        if ($request->rush_order) {
            $rush_order_fee = SiteSetting::where('key', $request->rush_order)->first();
            if (!empty($rush_order_fee)) {
                $rush_order_fee = $rush_order_fee->value;
                $data['rush_order'] = [
                    'type' => $request->rush_order,
                    'percentage' => $rush_order_fee,
                ];
            }
        }

        $order_total += $product_total;
        //Rush Order
        $rush_order_amount = $order_total * ($rush_order_fee ?? 0) / 100;
        $order_total += $rush_order_amount;

        //Calculate coupon discount
        if ($request->has('coupon_code')) {
            $coupon = Coupon::where('code', $request['coupon_code'])->first();

            if ($order && $order->coupon_id == $coupon->id) {
                $discount = [
                    'coupon' => $coupon,
                    'coupon_id' => $order->coupon_id,
                    'discount_type' => $order->discount_type,
                    'discount_value' => $order->discount_value,
                ];

                if ($order->discount_type == 'fixed') {
                    $discount['order_discount'] = $order->discount_value;
                } else {
                    $discount['order_discount'] = $order_total * ($order->discount_value ?? 0) / 100;
                }
            } else {
                $discount = [
                    'coupon' => $coupon,
                    'coupon_id' => $coupon->id,
                    'discount_type' => $coupon->discount_type,
                    'discount_value' => $coupon->discount_value,
                ];

                if ($coupon->discount_type == 'fixed') {
                    $discount['order_discount'] = $coupon->discount_value;
                } else {
                    $discount['order_discount'] = $order_total * ($coupon->discount_value ?? 0) / 100;
                }
            }

            $order_total -= $discount['order_discount'];
        }

        $state_tax  = $order_total * ($state_sales_tax ?? 0) / 100;

        $order_total += $shipping_amount;
        //Add sales tax in total if not waved off
        $order_total += $request->waive_off_sales_tax == 1 ? 0 : $state_tax;

        $data['rush_order']['amount'] = $rush_order_amount;

        $data['sales_tax'] = [
            'state' => $state->name,
            'percentage' => $state_sales_tax,
            'amount' => $state_tax,
        ];

        $data['discount'] = $discount;
        $data['engraving_fee_of_all_products'] = $engraving_fee_of_all_products;
        $data['shipping_charges'] = $shipping_amount;
        $data['grand_total'] = $order_total;

        return $data;
    }

    public function sendOrderStatusUpdatedMail($notes = null): void
    {
        $company_phone_1 = SiteSetting::where('key', 'Site Phone')->first();
        $company_phone_2 = SiteSetting::where('key', 'Site Phone 2')->first();

        $data = [
            'order_number' => $this->order_number,
            'tracking_number' => $this->tracking_number,
            'customer_name' => $this->user->name ?? '',
            'notes' => $notes,
            'company_phone_1' => $company_phone_1->value ?? "N/A",
            'company_phone_2' => $company_phone_2->value ?? "N/A",
            'invoice_path' => $this->invoice->invoicePath ?? '',
        ];

        if ($this->tracking_number != null) {
            $data['tracking_number'] = "https://www.ups.com/track?track=yes&trackNums=" . $this->tracking_number;
        }

        if ($this->current_status->name == "Order Acknowledgement") {

            if ($this->payment_status == "Unpaid") {
                $pj_invoice = generatePJInvoice($this);
                if ($this->payment_status == "Unpaid") {
                    $data['invoice_url'] =  $pj_invoice->hostedInvoiceUrl ?? null;
                }
            }
            $this->user->notify(new OrderApprovedConfirmedNotification($data));
        }/*  else if ($this->current_status->name == "In Production") {
            $this->user->notify(new OrderInProductionNotification($data));
        }else if ($this->current_status->name == "In Assembly/Cleaning") { //This email has been disabled by client
            $this->user->notify(new OrderInAssemblyCleaningNotification($data));
        }  else if ($this->current_status->name == "Waiting on customer") {
            $this->user->notify(new OrderWaitingOnCustomerNotification($data));
        }*/ else if ($this->current_status->name == "Complete/Customer Notified") {

            //Adding additional data required in email template
            $data['delivery_type'] = $this->delivery_type;

            $data['billing_details'] = [
                'Primary Contact Name' => $this->billing_primary_contact_name,
                'Primary Contact Email' => $this->billing_primary_contact_email,
                'Address' => $this->billing_address_line_1,
                'Other' => $this->billing_city . " " . $this->billing_state . " " . $this->billing_zipcode,
            ];

            if ($this->delivery_type == "Shipping") {
                $data['delivery_details'] = [
                    'Primary Contact Name' => $this->shipping_primary_contact_name,
                    'Primary Contact Email' => $this->shipping_primary_contact_email,
                    'Address' => $this->shipping_address_line_1,
                    'Other' => $this->shipping_city . " " . $this->shipping_state . " " . $this->shipping_zipcode,
                ];

                if ($this->tracking_number != null && $this->tracking_number != 'undefined') {
                    $data['tracking_number'] = "https://www.ups.com/track?track=yes&trackNums=" . $this->tracking_number;
                    $data['tracking_number_digits'] = $this->tracking_number;
                }
            } else {
                $data['delivery_details'] = [
                    'Pickup Location' => $this->pickLocation?->title,
                ];
            }

            if ($this->payment_status == "Paid") {
                $data = $this->getPaymentInfoData($data);
            } else {
                $pj_invoice = generatePJInvoice($this);
                if ($this->payment_status == "Paid") {
                    $data = $this->getPaymentInfoData($data);
                } else {
                    $data['payment_details'] = [
                        'Payment Status' => "Unpaid",
                        'Invoice URL'    => $pj_invoice->hostedInvoiceUrl ?? null,
                    ];
                }
            }

            $this->user->notify(new OrderCompletedNotification($data));
        } else if ($this->current_status->name == "Proof sent to customer") {
            $approve_url = config('app.react_app_artwork_approve_url');
            $templates = $attachments = [];
            foreach ($this->items as $item) {
                if (!empty($item->template)) {
                    $templates[] = '<li style="text-align: center; list-style: none"><strong><a href="' . asset('storage/order/' . $item->template) . '" style="text-decoration: underline; font-size: 25px; color: blue"><u>CLICK HERE TO VIEW ARTWORK</u></a></strong></li>';
                    $attachments[] = $item->templateUrl;
                }
            }
            $data = [
                'order_number' => $this->order_number,
                'user' => $this->user,
                'notes' => $this->notes,
                'approve_url' => $approve_url . $this->id,
                'templates' => $templates,
                'company_phone_1' => $company_phone_1->value ?? "N/A",
                'company_phone_2' => $company_phone_2->value ?? "N/A",
                'attachments' => $attachments,
            ];
            $this->user->notify(new OrderArtworkReminderNotification($data));
        } else if ($this->current_status->name == "Picked/Shipped") {
            //Need email verbiage for this
            if ($this->delivery_type == "Shipping") {
                if ($this->tracking_number != null && $this->tracking_number != 'undefined') {
                    $data['tracking_number'] = "https://www.ups.com/track?track=yes&trackNums=" . $this->tracking_number;
                    $data['tracking_number_digits'] = $this->tracking_number;
                    $data['picked_shipped'] = "Shipped";
                    $data['subject_title'] = "Order #{$this->order_number} Shipped - Exciting News";
                }
                $this->user->notify(new OrderPickedShippedNotification($data));
            }
        }/* else {
            $this->user->notify(new OrderStatusUpdatedNotification($data));
        }*/
    }

    public function updateOrderCalculation()
    {

        $items_total = 0;
        $shipping_amount = 0;

        $order_items = $this->items;

        if ($this->delivery_type == 'Shipping') {

            if ($this->career_code === "3ps") {
                $shipping_amount = (float)$this->shipping_total_amount;
            } else {
                $customer_id = config('app.web_ship_customer_id');
                $base_url = config('app.web_ship_base_url');
                $endpoint = "{$base_url}/customers/{$customer_id}/quote";

                $data_array = [
                    'shipping_address_id' => $this->shipping_address_id,
                    'career_code' => $this->career_code,
                    'service_code' => $this->service_code,
                    'package_type_code' => $this->package_type_code,
                    'is_residential' => true, //Need to store in order
                ];

                foreach ($order_items as $order_item) {
                    $data_array['products'][] = [
                        'price_id' => $order_item->price_id,
                        'quantity' => $order_item->quantity,
                    ];
                }

                $request = new Request();
                $request->merge($data_array);

                $request_body = prepareDataForShippingQuote($request);
                $response = getShippingQuoteServices($request_body, $endpoint);
                if ($response['data']) {
                    $shipping_amount = $response['data']['totalAmount'];
                }
            }
        }

        foreach ($order_items as $order_item) {
            $items_total += $order_item->total_price_after_engraving;
        }

        $grand_total = $items_total;
        $rush_order_amount = $items_total * ($this->rush_order_fee ?? 0) / 100;
        $grand_total += $rush_order_amount;

        //Recalculate discount here
        if ($this->coupon_id != null) {
            if ($this->discount_type == 'fixed') {
                $discount = $this->discount_value;
            } else {
                $discount = $grand_total * ($this->discount_value ?? 0) / 100;
            }
            $this->discount_total = $discount;
            $grand_total -= $discount;
        }

        $state_tax    = $grand_total * ($this->state_sales_tax ?? 0) / 100;
        $grand_total += $state_tax;

        $this->items_total = $items_total;
        $this->rush_order_amount = $rush_order_amount;
        $this->shipping_charges  = $shipping_amount;
        $this->sales_tax_amount  = $state_tax;
        $this->grand_total = $grand_total;
        $this->remaining_order_amount = $grand_total - $this->paid_order_amount;
        $this->save();
    }

    public function scopePreviousMonth($query)
    {
        $start_date = now()->startOfMonth()->subMonth();
        $end_date = now()->endOfMonth()->subMonth();
        $query->whereBetween('created_at', [$start_date, $end_date]);
    }

    public function scopeCurrentMonth($query)
    {
        $start_date = now()->startOfMonth();
        $end_date = now()->endOfMonth();
        $query->whereBetween('created_at', [$start_date, $end_date]);
    }

    public function scopePreviousYear($query)
    {
        $start_date = now()->startOfYear()->subYear();
        $end_date = now()->endOfYear()->subYear();
        $query->whereBetween('created_at', [$start_date, $end_date]);
    }

    public function scopeCurrentYear($query)
    {
        $start_date = now()->startOfYear();
        $end_date = now()->endOfYear();
        $query->whereBetween('created_at', [$start_date, $end_date]);
    }

    public function scopeUntilToday($query)
    {
        return $query;
    }

    public function partialPayments()
    {
        return $this->hasMany(OrderPartialPayments::class, 'order_id');
    }

    /**
     * @param $data
     * @return mixed
     */
    public function getPaymentInfoData($data): mixed
    {
        $data['payment_details'] = [
            "Payment Status" => "Paid",
            "Payment Type" => $this->payment_type,
        ];

        if ($this->payment_type == "Purchase Order") {
            $data['payment_details']['Purchase Order Number'] = $this->purchase_order_number;
            $data['payment_details']['Purchase Order Copy'] = $this->purchase_order_copy_url ?? 'N/A';
        } else if ($this->payment_type == "Check") {
            $data['payment_details']['Check Number'] = $this->cheque_number;
        } else if ($this->payment_type == "Credit Card") {
            $data['payment_details'] = $this->payment ? [
                'Card Type' => $this->payment->account_type,
                'Last Four' => $this->payment->last_four,
                'Payment Date' => $this->payment->created_at->format('Y-m-d'),
            ] : [];
        }
        return $data;
    }

    public function copyOrderNotes($order_id)
    {
        $order = Order::find($order_id);
        foreach ($order->notes as $note) {
            $note_clone = $note->replicate();
            $note_clone->order_id = $this->id;
            $note_clone->save();

            $media = $note->getMedia('*');
            foreach ($media as $media_item) {
                // Copy the file to the new model's media collection
                $note_clone->addMedia($media_item->getPath())
                    ->preservingOriginal()
                    ->toMediaCollection('note_attachments', 'order');
            }
        }
    }
}