File "Helper.php"

Full Path: /home/clickysoft/public_html/jmapi5.clickysoft.net/app/Helpers/Helper.php
File size: 28.72 KB
MIME-type: text/x-php
Charset: utf-8

<?php

use App\Models\AddressBook;
use App\Models\Coupon;
use App\Models\Order;
use App\Models\PayJunctionPayments;
use App\Models\ProductPrice;
use App\Models\User;
use Carbon\Carbon;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Symfony\Component\HttpFoundation\Response as HTTPResponse;

if (!function_exists('getShippingQuoteServices')) {
    function getShippingQuoteServices($request_body, $endpoint): array
    {
        $api_key = config('app.web_ship_api_key');
        $client = new Client();

        $headers = [
            'Authorization' => $api_key,
            'accept' => 'application/json',
            'Content-Type' => 'application/json',
        ];
        try {

            $request = new \GuzzleHttp\Psr7\Request('POST', $endpoint, $headers, json_encode($request_body));
            $res = $client->sendAsync($request)->wait();
            $statusCode = $res->getStatusCode();

            if ($statusCode == 200) {
                $response = json_decode($res->getBody(), true);
                $data = [];
                if (isset($response['quotes'])) {
                    foreach ($response['quotes'] as $value) {
                        if (array_key_exists($value['serviceCode'], Order::DELIVERY_PACKAGES)) {
                            $data[] = [
                                "carrierCode" => $value['carrierCode'],
                                "serviceCode" => $value['serviceCode'],
                                "serviceDescription" => $value['serviceDescription'],
                                "visualDescription" => Order::DELIVERY_PACKAGES[$value['serviceCode']] . ' - $' . $value['totalAmount'],
                                "packageTypeCode" => $value['packageTypeCode'],
                                "currency" => $value['currency'],
                                "totalAmount" => $value['totalAmount'],
                            ];
                        }
                    }
                } else {
                    $data = $response;
                };

                return [
                    'success' => true,
                    'data' => $data
                ];
            } else {
                return [
                    'success' => false,
                    'data' => []
                ];
            }
        } catch (GuzzleException $exception) {
            Log::info('getShippingQuoteServices error');
            Log::info($exception->getMessage());
            return [
                'success' => false,
                'data' => []
            ];
        }
    }
}

if (!function_exists('prepareDataForShippingQuote')) {
    function prepareDataForShippingQuote(Request $request): array
    {
        $shipping_address = AddressBook::find($request->get('shipping_address_id'));

        $request_body = [
            "carrierCode" => $request->get('career_code', 'ups'), //ups
            "serviceCode" => $request->get('service_code', ''), //ups_ground
            "packageTypeCode" => $request->get('package_type_code', ''), //ups_custom_package
            "residential" => (bool) $request->get('is_residential'),
            "signatureOptionCode" => null,
            "sender" => [
                "country" => "US",
                "zip" => "92373"
            ],
            "receiver" => [
                "country" => "US",
                "zip" => $shipping_address->zipcode ?? $request->get('zipcode'),
            ],
            "weightUnit" => "lb",
            "dimUnit" => "in",
            "currency" => "USD",
            "customsCurrency" => "USD",
        ];

        $pieces = [];

        foreach ($request->get('products') as $product) {
            $price = ProductPrice::find($product['price_id']);
            for ($i = 0; $i < $product['quantity']; $i++) {
                $pieces[] = [
                    'weight' => (string) $price->shipping_weight,
                    'length' => $price->length ?? null,
                    'width' => $price->width ?? null,
                    'height' => $price->height ?? null,
                    'insuranceAmount' => null,
                    'declaredValue' => null,
                ];
            }
        }

        $request_body['pieces'] = $pieces;
        return $request_body;
    }
}

if (!function_exists('reportDateRange')) {
    function reportDateRange(Request $request): array
    {
        switch ($request->get('report_type')) {
            case 'daily':
                $start_year = $request->get('date');
                $date_range = [
                    'year_from' => Carbon::createFromFormat('Y-m-d', $start_year)->startOfDay(),
                    'year_to' => Carbon::createFromFormat('Y-m-d', $start_year)->endOfDay(),
                ];
                break;
            case 'weekly':
                $start_year = $request->get('date');
                $date_range = [
                    'year_from' => Carbon::createFromFormat('Y-m-d', $start_year)->startOfDay(),
                    'year_to' => Carbon::createFromFormat('Y-m-d', $start_year)->addDays(6)->endOfDay(),
                ];
                break;
            case 'monthly':
                $start_year = $request->get('date');
                $date_range = [
                    'year_from' => Carbon::make($start_year)->startOfMonth(),
                    'year_to' => Carbon::make($start_year)->endOfMonth(),
                ];
                break;
            case 'current_year':
                $date_range = [
                    'year_from' => now()->startOfYear(),
                    'year_to' => now()->endOfYear(),
                ];
                break;
            case 'current_month':
                $date_range = [
                    'year_from' => now()->startOfMonth(),
                    'year_to' => now()->endOfMonth(),
                ];
                break;
            case 'previous_month':
                $date_range = [
                    'year_from' => now()->subMonth()->startOfMonth(),
                    'year_to' => now()->subMonth()->endOfMonth(),
                ];
                break;
            case 'custom':
                $start_year = $request->get('year_from');
                $end_year = $request->get('year_to');
                $date_range = [
                    'year_from' => Carbon::createFromFormat('Y-m-d', "$start_year-01-01"),
                    'year_to' => Carbon::createFromFormat('Y-m-d', "$end_year-12-31"),
                ];
                break;
            default:
                $date_range = [
                    'year_from' => now()->startOfYear()->subYear(),
                    'year_to' => now()->endOfYear()->subYear(),
                ];
                break;
        }

        return $date_range;
    }
}

function getPJClient(): Client
{
    $pj_user = config("app.pj_user");
    $pj_pass = config("app.pj_pass");
    $pj_app_key = config("app.pj_key");

    $headers = [
        "X-PJ-Application-Key" => $pj_app_key,
        "Authorization" => "Basic " . base64_encode("{$pj_user}:{$pj_pass}"),
    ];
    return new Client([
        'base_uri' => config("app.pj_url"),
        "headers" => $headers,
    ]);
}

if (!function_exists('createPJCustomer')) {
    function createPJCustomer($billing_address_id, User $user): bool
    {

        $client = getPJClient();
        $billingAddress = AddressBook::find($billing_address_id);

        $data = [
            "firstName" => $billingAddress->primary_contact_name,
            "email" => $billingAddress->primary_contact_email,
            "address" => $billingAddress->address_line_1,
            "zip" => $billingAddress->zipcode,
        ];

        try {
            $res = $client->post("/customers", ["form_params" => $data]);

            if ($res->getStatusCode() == 200) {
                $contents = json_decode($res->getBody()->getContents());

                $user->update(['pj_customer_id' => $contents->customerId]);
                $user->save();
                return true;
            } else {
                return false;
            }
        } catch (GuzzleException $e) {
            Log::info('Pay Junction Create Customer Error');
            Log::info($e->getMessage());
            return false;
        }
    }
}

if (!function_exists('createPJCustomerVault')) {
    function createPJCustomerVault(User $user, $billing_address_id, $card_data): array
    {
        $billingAddress = AddressBook::find($billing_address_id);
        $data = [
            "cardNumber" => $card_data['cardNumber'],
            "cardExpMonth" => $card_data['cardExpMonth'],
            "cardExpYear" => $card_data['cardExpYear'],
            "cvv" => $card_data['cvv'],
            "address" => $billingAddress->address_line_1,
            "zip" => $billingAddress->zipcode,
        ];

        $client = getPJClient();

        try {
            $res = $client->post("/customers/{$user->pj_id}/vaults", ["form_params" => $data]);

            if ($res->getStatusCode() == 200) {
                $contents = json_decode($res->getBody()->getContents());
                return [
                    'success' => true,
                    'vault_id' => $contents->vaultId,
                ];
            } else {
                return [
                    'success' => false,
                    'error' => 'Could not create customer vault.',
                ];
            }
        } catch (GuzzleException $e) {
            Log::info('Pay Junction Create Customer Vault Error');
            Log::info($e->getMessage());
            return [
                'success' => false,
                'vault_id' => 'Unable to create customer vault.',
            ];
        }
    }
}

if (!function_exists('chargeByVaultId')) {
    function chargeByVaultId($billing_address_id, $vault_id, $amount): array
    {
        $billingAddress = AddressBook::find($billing_address_id);
        $details = [
            "vaultId" => $vault_id,
            "action" => "CHARGE",
            "amountBase" => number_format($amount, 2, '.', ''),
            "billingAddress" => $billingAddress->address_line_1,
            "billingZip" => $billingAddress->zipcode,
            "invoiceNumber" => time()
        ];

        try {
            $client = getPJClient();
            $res = $client->post("/transactions", ["form_params" => $details]);

            if (!$res->getStatusCode() == 200) {
                return [
                    'success' => false,
                    'error' => 'Unable to process payment.',
                ];
            }

            $response = json_decode($res->getBody()->getContents());

            if (!$response?->response?->approved) {
                return [
                    'success' => false,
                    'error' => $response?->response?->message,
                ];
            }

            $transactionData = [
                "transaction_id" => $response->transactionId,
                "terminal_id" => $response->terminalId,
                "action" => $response->action,
                "amount_base" => $response->amountBase,
                "amount_total" => $response->amountTotal,
                "method" => $response->method,
                "status" => $response->status,
                "approved" => $response?->response?->approved,
                "message" => $response?->response?->message,
                "account_type" => $response?->vault?->accountType,
                "last_four" => $response?->vault?->lastFour,
            ];

            $rec = PayJunctionPayments::create($transactionData);
            return [
                'success' => true,
                'response' => $rec,
            ];
        } catch (GuzzleException $e) {
            Log::info('Pay Junction Charge Via Vault Error');
            Log::info($e->getMessage());
            return [
                'success' => false,
                'error' => 'Unable to process payment.',
            ];
        }
    }
}

if (!function_exists('chargeByCard')) {
    function chargeByCard($billing_address_id, $amount, $data)
    {
        $billingAddress = AddressBook::find($billing_address_id);
        $cardData = [
            "cardNumber" => $data['card_number'], //Valid Credit Card Number.
            "cardExpMonth" => $data['expiry_month'], //1-12, Ex: 8
            "cardExpYear" => $data['expiry_year'], //4 Digit Format. Ex: 2015
            "cardCvv" => $data['ccv'], //Valid CVV. Max Length 4
        ];

        $exploded = explode(" ", $billingAddress->primary_contact_name);
        $first_name = $exploded[0];
        unset($exploded[0]);
        $last_name = implode(' ', $exploded);

        $otherFields = [
            "status" => "CAPTURE",
            "action" => "CHARGE",
            "amountBase" => number_format($amount, 2, '.', ''),
            "billingFirstName" => $first_name,
            "billingAddress" => $billingAddress->address_line_1,
            "billingZip" => $billingAddress->zipcode,
            "invoiceNumber" => time(),
        ];

        if ($last_name != '') {
            $otherFields['billingLastName'] = $last_name;
        }

        try {
            $client = getPJClient();
            $res = $client->post("/transactions", ["form_params" => array_merge($cardData, $otherFields)]);
            if ($res->getStatusCode() == 200) {
                $response = json_decode($res->getBody()->getContents());

                if (!$response?->response?->approved) {
                    return [
                        'success' => false,
                        'error' => $response?->response?->message,
                    ];
                }

                $transactionData = [
                    "transaction_id" => $response->transactionId,
                    "terminal_id" => $response->terminalId,
                    "action" => $response->action,
                    "amount_base" => $response->amountBase,
                    "amount_total" => $response->amountTotal,
                    "method" => $response->method,
                    "status" => $response->status,
                    "approved" => $response?->response?->approved,
                    "message" => $response?->response?->message,
                    "account_type" => $response?->vault?->accountType,
                    "last_four" => $response?->vault?->lastFour,
                ];

                $rec = PayJunctionPayments::create($transactionData);
                return [
                    'success' => true,
                    'response' => $rec,
                ];
            }
        } catch (GuzzleException $e) {
            Log::info('Pay Junction Charge Via Card Error');
            Log::info($e->getMessage());
            return [
                'success' => false,
                'error' => isset(json_decode($e->getResponse()->getBody(true))->errors[0]->message)
                    ? json_decode($e->getResponse()->getBody(true))->errors[0]->message
                    : 'Unable to process payment.',
            ];
        }
    }
}

if (!function_exists('getCustomerVaults')) {
    function getCustomerVaults($customer_id)
    {
        $client = getPJClient();
        $customer_vaults = [];
        try {

            $api_response = $client->get("/customers/{$customer_id}/vaults");
            if ($api_response->getStatusCode() == 200) {
                $response = json_decode($api_response->getBody()->getContents());
                foreach ($response->results as $card) {
                    $customer_vaults[] = [
                        'vault_id' => $card->vaultId,
                        'type' => $card->type,
                        'account_type' => $card->accountType,
                        'last_four' => $card->lastFour,
                        'expiry_month' => $card->cardExpMonth,
                        'expiry_year' => $card->cardExpYear,
                    ];
                }
                return $customer_vaults;
            }
        } catch (GuzzleException $e) {
            Log::info('Pay Junction Get Customer Vaults. ID : ' . $customer_id);
            Log::info($e->getMessage());
            return $customer_vaults;
        }
    }
}

function createPJInvoice($data)
{
    $client = getPJClient();
    $details = [
        'amountBase' => $data['amount'],
        'customerEmail' => $data['customer_email'],
        'message' => 'Invoice for order #' . $data['order_number'],
        'terminalId' => config('app.pj_tid'),
        'notificationType' => 'NONE',
    ];
    try {
        $api_response = $client->post("/invoices", ["form_params" => $details]);
        if ($api_response->getStatusCode() == 200) {
            return json_decode($api_response->getBody()->getContents());
        }
    } catch (GuzzleException $e) {
        Log::info('Pay Junction Create Invoice Error');
        Log::info($e->getMessage());
        return null;
    }
}

function getPJInvoice($invoice_id)
{
    $client = getPJClient();

    try {
        $api_response = $client->get("/invoices/$invoice_id");
        if ($api_response->getStatusCode() == 200) {
            return json_decode($api_response->getBody()->getContents());
        }
    } catch (GuzzleException $e) {
        Log::info('Pay Junction Get Invoice Error');
        Log::info($e->getMessage());
        return null;
    }
}

function voidPJInvoice($invoice_id)
{
    $client = getPJClient();

    try {
        $api_response = $client->post("/invoices/$invoice_id/void");
        if ($api_response->getStatusCode() == 200) {
            return true;
        }
    } catch (GuzzleException $e) {
        Log::info('Pay Junction Void Invoice Error');
        Log::info($e->getMessage());
        return null;
    }
}

if (!function_exists('generatePJInvoice')) {
    function generatePJInvoice(Order $order)
    {
        $response = null;

        if ($order->remaining_order_amount > 0 && $order->remaining_order_amount < 1) {
            $order->payment_status = 'Paid';
            $order->remaining_order_amount = 0;
            $order->paid_order_amount = $order->grand_total;
            $order->payment_date = new DateTime();
            $order->save();
        } else {
            $formated_remaining_amount = (float) number_format($order->remaining_order_amount, 2, '.', '');
            //Get invoice if exists
            $data = [
                'amount' => $formated_remaining_amount,
                'customer_email' => $order->user->email,
                'order_number' => $order->order_number,
            ];

            if ($order->pj_invoice_id == null) { // If an invoice doesn't exist for this order
                $response = createPJInvoice($data); // Create a new invoice
                if ($response) {
                    $order->pj_invoice_id = $response->invoiceId;
                    $order->save();
                }
            } else {
                $pj_invoice = getPJInvoice($order->pj_invoice_id);
                if ($pj_invoice->status == "OPEN") { // If the invoice is created but not paid yet
                    if ($pj_invoice->amountBase == $formated_remaining_amount) { //Do not create new invoice if amount is same
                        $response = $pj_invoice;
                    } else {  // Void the previous invoice and create a new one with updated data
                        voidPJInvoice($pj_invoice->invoiceId);
                        Log::channel('info_errors')->info("PJ invoice ID $order->pj_invoice_id will removed for order id $order->id.");
                        $order->pj_invoice_id = null;
                        $order->save();
                        if ($response = createPJInvoice($data)) {
                            $order->pj_invoice_id = $response->invoiceId;
                            $order->save();
                            Log::channel('info_errors')->info("PJ invoice new ID $order->pj_invoice_id for order id $order->id.");
                        }
                    }
                } else if ($pj_invoice->status == "PAID") { // If the invoice is already paid
                    $order->payment_status = 'Paid';
                    $order->remaining_order_amount = 0;
                    $order->paid_order_amount = $order->grand_total;
                    $order->payment_date = new DateTime();
                    $order->save();
                }
            }
        }

        return $response; // Return the invoice response
    }
}

if (!function_exists('validateCouponDetails')) {
    function validateCouponDetails($code)
    {

        $coupon = Coupon::where('code', $code)->where('status', 1)->first();

        if (!$coupon) {
            return [
                'coupon' => null,
                'code' => HTTPResponse::HTTP_OK,
                'message' => "Invalid coupon code.",
                'errors' => ["error" => ["Invalid coupon."]]
            ];
        }

        if ($coupon->expiry_date) {
            $day_end = $coupon->expiry_date->endOfDay();
            if (!now()->lte($day_end)) {
                return [
                    'coupon' => null,
                    'code' => HTTPResponse::HTTP_OK,
                    'message' => "Coupon has expired.",
                    'errors' => ["error" => ["Coupon has expired."]]
                ];
            }
        }

        if ($coupon->number_of_usage > 0 && $coupon->redemption_count >= $coupon->number_of_usage) {
            return [
                'coupon' => null,
                'code' => HTTPResponse::HTTP_OK,
                'message' => "Coupon usage limit reached.",
                'errors' => ["error" => ["Coupon usage limit reached."]]
            ];
        }

        return [
            'coupon' => [
                'type' => $coupon->discount_type,
                'value' => $coupon->discount_value,
            ],
            'code' => HTTPResponse::HTTP_OK,
            'message' => "Coupon is valid.",
            'errors' => ["error" => []]
        ];
    }
}

if (!function_exists('pdfToImages')) {
    function pdfToImages($order_id, $item_id, $template_path): void
    {
        $folder_name = $order_id . '_' . $item_id;
        $imagick = new \Imagick();

        if (Storage::disk('order')->exists("$order_id/$folder_name")) {
            Storage::disk('order')->deleteDirectory("$order_id/$folder_name");
        }

        Storage::disk('order')->makeDirectory("$order_id/$folder_name");

        $path = Storage::disk('order')->path("$order_id/$folder_name");

        $imagick->readImage(Storage::disk('order')->path($template_path));
        $format = "png";
        $imagick->setImageFormat($format);

        foreach ($imagick as $pageNumber => $page) {
            $image = $page->clone();
            $image->setIteratorIndex((int)$pageNumber);
            $image->writeImage($path . '/page_' . ($pageNumber + 1) . '.' . $format);
        }

        $imagick->clear();
    }
}

if (!function_exists('getTemplatePngs')) {
    function getTemplatePngs($order_id, $item_id)
    {
        $folder_name = $order_id . '_' . $item_id;
        $disk = 'order';
        $pngUrls = [];

        if (!Storage::disk('order')->exists("$order_id/$folder_name")) {
            return $pngUrls;
        }

        $files = Storage::disk($disk)->files("$order_id/$folder_name");

        foreach ($files as $file) {
            $pngUrls[] = Storage::disk($disk)->url($file);
        }

        return $pngUrls;
    }
}

function handleOrderCharge($request, $order_totals): array
{

    //Charge via vault_id if we are receiving vault_id
    if ($request->get('vault_id')) {
        //Charge customer using vault it just created.
        $charge_response = chargeByVaultId(
            $request->get('billing_address_id'),
            $request->get('vault_id'),
            $order_totals['grand_total'],
        );

        if (!$charge_response['success']) {
            return [
                'charged_successfully' => false,
                'message' => "Can not create order.",
                'errors' => ["error" => $charge_response["error"]],
                'error_code' => HTTPResponse::HTTP_INTERNAL_SERVER_ERROR
            ];
        }

        $charge_response['charged_successfully'] = true;
    } else {
        //If customers allowed to save card
        if ($request->get('save_card', false)) {
            $customer = User::find($request->get('user_id'));
            //Check if PayJunction customerId exists. Create if not present.
            if (!$customer->pj_id) {
                $customerCreated = createPJCustomer(
                    $request->get('billing_address_id'),
                    $customer
                );

                if (!$customerCreated) {
                    return [
                        'charged_successfully' => false,
                        'message' => "Can not create order.",
                        'errors' => ["error" => ["Customer creation failed."]],
                        'error_code' => HTTPResponse::HTTP_INTERNAL_SERVER_ERROR
                    ];
                }
            }

            $card_data = [
                "cardNumber" => $request->get('card_number'),
                "cardExpMonth" => $request->get('expiry_month'),
                "cardExpYear" => $request->get('expiry_year'),
                "cvv" => $request->get('ccv')
            ];

            $vaultId = createPJCustomerVault(
                $customer,
                $request->get('billing_address_id'),
                $card_data,
            );

            if (!$vaultId['success']) {
                return [
                    'charged_successfully' => false,
                    'message' => "Can not create order.",
                    'errors' => ["error" => ["Customer vault creation failed. Make sure you enter valid card credentials."]],
                    'error_code' => HTTPResponse::HTTP_INTERNAL_SERVER_ERROR
                ];
            }
            //Charge customer using vault it just created.
            $charge_response = chargeByVaultId(
                $request->get('billing_address_id'),
                $vaultId['vault_id'],
                $order_totals['grand_total'],
            );

            $charge_response['charged_successfully'] = true;
        } else {
            //Charge by card information
            $card_data = [
                'card_number' => $request->get('card_number'),
                'expiry_month' => $request->get('expiry_month'),
                'expiry_year' => $request->get('expiry_year'),
                'ccv' => $request->get('ccv'),
            ];
            $charge_response = chargeByCard(
                $request->get('billing_address_id'),
                $order_totals['grand_total'],
                $card_data
            );
        }
        if (!$charge_response['success']) {
            return [
                'charged_successfully' => false,
                'message' => "Can not create order.",
                'errors' => ["error" => $charge_response["error"]],
                'error_code' => HTTPResponse::HTTP_INTERNAL_SERVER_ERROR
            ];
        } else {
            $charge_response['charged_successfully'] = true;
        }
    }

    return $charge_response;
}

function getOrderShippingResponse($request): array
{
    $shipping_data = [];
    if ($request->has("third_party_shipping")) {
        $shipping_data = [
            'career_code' => '3ps',
            'service_code' => "3rd party shipping",
            'package_type_code' => "3rd party shipping",
            'shipping_charges' => (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_data = [
                'career_code' => $response['data']['carrierCode'],
                'service_code' => $response['data']['serviceCode'],
                'package_type_code' => $response['data']['packageTypeCode'],
                'shipping_charges' => $response['data']['totalAmount'],
            ];
        }
    }

    return $shipping_data;
}

function updatePJTransaction($transaction_id, $invoice_number)
{
    try {
        $client = getPJClient();
        $details = ['invoiceNumber' => $invoice_number];
        $client->put("/transactions/$transaction_id", ["form_params" => $details]);
        return ['success' => true];
    } catch (GuzzleException $exception) {
        Log::info('Unable to update PJ transaction: ' . $exception->getMessage());
        return ['success' => false];
    }
}

function voidPJTransaction($transaction_id)
{
    try {
        $client = getPJClient();
        $details = ['status' => 'VOID'];
        $client->put("/transactions/$transaction_id", ["form_params" => $details]);
        return ['success' => true];
    } catch (GuzzleException $exception) {
        Log::info('Unable to void PJ transaction: ' . $exception->getMessage());
        return ['success' => false];
    }
}