HOME


Mini Shell 1.0
Redirecting to https://devs.lapieza.net/iniciar-sesion Redirecting to https://devs.lapieza.net/iniciar-sesion.
DIR: /var/www/devs.lapieza.net/app/Http/Controllers/Api/TransporteBlanco/V1/
Upload File :
Current File : /var/www/devs.lapieza.net/app/Http/Controllers/Api/TransporteBlanco/V1/PricingController.php
<?php

namespace App\Http\Controllers\Api\TransporteBlanco\V1;

use App\Http\Controllers\Controller;
use App\Http\Controllers\Delivery\PedidosYaController;
use App\Http\Requests\Api\TransporteBlanco\PricingRequest;
use App\Models\Address;
use App\Models\Product;
use App\Models\ShippingCost;
use App\Models\TransporteBlancoPueblo;
use App\Models\TransporteBlancoZona;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Support\Facades\Log;

class PricingController extends Controller {
    private const AVAILABLE_AREAS = [
        'Santo Domingo',
        'Santo Domingo Este',
        'Santo Domingo Norte',
        'Santo Domingo Oeste',
        'Distrito Nacional',
        'Pedro Brand',
        'Los Alcarrizos',
        'San Antonio de Guerra',
        'Boca Chica'
    ];
    private const MAX_VOLUME = (19 * 2.54) * (12 * 2.54) * (12 * 2.54);
    private const TB_ADDRESS_SD_RD = [
        'address' => 'Av. Los Beibolistas, Esq. Jafres',
        'city' => 'Santo Domingo',
        'state' => 'Santo Domingo',
        'latitude' => 18.48402381193991,
        'longitude' => -69.982946712279,
        'phone' => '+8093791670',
    ];
    private static ShippingCost $shippingCost;

    public function pricing(PricingRequest $request) {
        $response = [];
        $customerId = $request->customerId;
        $product = Product::find($request->productId);
        $quantity = $request->quantity;
        $response['estimated_pickup_time'] = self::estimatePickupTime();
        $town = strtoupper($request->city);
        $buyerAddress = self::getBuyerAddress($customerId);
        $addressForPedidosYa = Address::make(self::TB_ADDRESS_SD_RD);
        $body = self::buildBody($request, $product, $quantity, $addressForPedidosYa);
        $pueblo = TransporteBlancoPueblo::where('nombre', $town)
            ->orWhere(function ($query) use ($request) {
                $query->where('latitud', $request->latitude)
                    ->where('longitud', $request->longitude);
            })->first();
        if (self::isLocalDelivery($buyerAddress)) {
            return response()->json(self::createLocalDelivery($response, $request, $body, $product));
        }

        if (!$pueblo) {
            $ciudad = TransporteBlancoZona::where('nombre', 'like', '%' . $request->state . '%')->first();
            Log::alert($request->state);
            Log::alert($ciudad);
            if ($ciudad) {
                \Log::alert('ciudad');
                $response = self::buildResponse(
                    $response,
                    $ciudad->nombre,
                    self::calcCosts($product, $customerId, $quantity, $ciudad, $body, false),
                    self::estimateDropOffTime($response['estimated_pickup_time'], false)
                );
            }
            \Log::alert('nada');
        } else {
            \Log::alert('pueblo');
            $response = self::buildResponse(
                $response,
                $pueblo->nombre,
                self::calcCosts($product, $customerId, $quantity, $pueblo, $body),
                self::estimateDropOffTime($response['estimated_pickup_time'], true, $pueblo)
            );
        }
        return response()->json($response);
    }

    private static function estimatePickupTime() {
        $date = Carbon::today()->timezone('America/Santo_Domingo')->addDay();
        while ($date->isWeekend()) {
            $date->addDay();
        }
        return $date->format('Y-m-d H:i:s');
    }

    private static function getBuyerAddress($customerID): Address {
        return User::find($customerID)->addresses()->where('set_default', 1)->first();
    }

    private static function buildBody($request, $product, $quantity, $addressForPedidosYa) {
        return [
            'customerId' => $request->customerId,
            'product' => $product,
            'quantity' => $quantity,
            'totalWeight' => self::calcTotalWeight($product, $quantity),
            'totalVolume' => self::extractVolume($product),
            'sellerAddress' => self::getSellerAddress($product),
            'buyerAddress' => $addressForPedidosYa,
            'availableAreas' => self::AVAILABLE_AREAS,
        ];
    }

    private static function calcTotalWeight(Product $product, $quantity): float {
        return $product->weight * $quantity;
    }

    private static function extractVolume(Product $product): float {
        $choise_options = json_decode($product->choice_options);
        $envelope = trim(str_replace('SOBRE', '', $choise_options[0]->values[0]));
        return match ($envelope) {
            'A' => self::calcVolume(4.7, 8.4, 2.4),
            'B' => self::calcVolume(5.9, 8.4, 2.4),
            'C' => self::calcVolume(7, 10.4, 2.4),
            'D' => self::calcVolume(8.6, 10.4, 2.4),
            'E' => self::calcVolume(9, 13.3, 2.4),
            'F' => self::calcVolume(9.4, 13.1, 2.4),
            'G' => self::calcVolume(10.6, 8.4, 14.1),
            'H' => self::calcVolume(11.8, 17.5, 2.4),
            'I' => self::calcVolume(13.7, 18.5, 2.4),
            'J' => self::calcVolume(7, 6.4, 2.4),
            default => 0.00,
        };
    }

    private static function calcVolume(int|float $length, int|float $width, int|float $height): float {
        $length_to_cm = $length * 2.54;
        $width_to_cm = $width * 2.54;
        $height_to_cm = $height * 2.54;
        return $length_to_cm * $width_to_cm * $height_to_cm;
    }

    private static function getSellerAddress(Product $product): Address|bool {
        return $product->user->addresses()->where('set_default', 1)->first();
    }

    private static function isLocalDelivery($buyerAddress): bool {
        return in_array($buyerAddress->city, self::AVAILABLE_AREAS);
    }

    private static function createLocalDelivery($response, $request, $body, $product) {
        $cart = $product->carts()->where('user_id', $request->customerId)->first();
        if (!$cart) {
            throw new HttpResponseException(response()->json(['message' => 'NOT_PRODUCT_IN_CART'], 404));
        }
        if (PedidosYaController::checkAvailability($body)) {
            $body['isTransferred'] = true;
            $pedidosYa = PedidosYaController::make($body);
            $price = 240.00 + $pedidosYa['delivery']['starter_price'];
            self::createShippingCost($pedidosYa, $cart, $body, $price);
        } else {
            $body['isTransferred'] = false;
            $price = 240.00 + 350.00;
            self::createShippingCost(null, $cart, $body, $price);
        }
        return self::buildResponse(
            $response,
            $request->city,
            self::calcCosts($product, $request->customerId, $request->quantity, $request->city, $body, false),
            self::estimateDropOffTime($response['estimated_pickup_time'], false)
        );
    }

    private static function createShippingCost($pedidosYa, $cart, $body, $price = 0.00) {
        $price = self::calcExtraPrice($cart->product->weight, self::extractVolume($cart->product), $price);
        if (($body['product']->unit_price * $body['quantity']) > 2000.00) {
            $secureDifference = ($body['product']->unit_price * $body['quantity']) - 2000.00;
        }
        $shippingCost = ShippingCost::make([
            'starter_price' => $price,
            'ending_price' => $price + ($price * 0.25),
            'pedidosya_secure_difference' => $secureDifference ?? 0.00,
            'cart_id' => $cart->id,
            'shipping_company' => 'Transporte Blanco'
        ]);
        if ($body['isTransferred']) {
            $isSaved = $cart->shippingCosts()
                ->where('shipping_company', 'TRANSPORTE BLANCO')
                ->exists();
            if ($isSaved) {
                $oldShippingCost = $cart->shippingCosts()
                    ->where('shipping_company', 'TRANSPORTE BLANCO')
                    ->where('require_transfer', true)
                    ->first();
                if ($oldShippingCost->expiration_date < Carbon::now('America/Santo_Domingo')) {
                    $response = PedidosYaController::make($body);
                    $shippingCost->update([
                        'shipping_id' => $response['delivery']['estimateId'],
                        'delivery_offer_id' => $response['delivery']['deliveryOfferId'],
                        'pedidosya_secure_difference' => $secureDifference ?? 0.00,
                        'expiration_date' => $response['delivery']['confirmationTimeLimit'],
                        'require_transfer' => $body['isTransferred']
                    ]);
                }
                $shippingCost = $oldShippingCost;
            } else {
                $shippingCost->fill([
                    'shipping_id' => $pedidosYa['delivery']['estimateId'],
                    'delivery_offer_id' => $pedidosYa['delivery']['deliveryOfferId'],
                    'pedidosya_secure_difference' => $secureDifference ?? 0.00,
                    'expiration_date' => $pedidosYa['delivery']['confirmationTimeLimit'],
                    'require_transfer' => $body['isTransferred']
                ]);
                $shippingCost->save();
            }
        } else {
            if ($cart->shippingCosts()->where('shipping_company', 'TRANSPORTE BLANCO')->exists()) {
                $cart->shippingCosts()
                    ->where('shipping_company', 'TRANSPORTE BLANCO')
                    ->first()
                    ->delete();
            }
            $shippingCost->save();
        }
        self::$shippingCost = $shippingCost;
    }

    private static function calcExtraPrice($totalWeight, $totalVolume, $initialPrice) {
        $price = $initialPrice;
        if ($totalWeight > 40.00 && $totalWeight < 150.00) {
            $totalWeightExceeded = $totalWeight - 40.00;
            $extraWeightPrice = $totalWeightExceeded * 10.00;
            $price += $extraWeightPrice;
        }
        if ($totalVolume > self::MAX_VOLUME) {
            $actualVolumeOnPie = $totalVolume / 30.48;
            $maxVolumeOnPie = self::MAX_VOLUME / 30.48;
            $volumeExceeded = $actualVolumeOnPie - $maxVolumeOnPie;
            $extraVolumePrice = $volumeExceeded * 30.00;
            $price += $extraVolumePrice;
        }
        return $price;
    }

    private static function buildResponse($response, $to, $price, $dropoff_time) {
        $pickup_time = $response['estimated_pickup_time'];
        unset($response['estimated_pickup_time']);
        return [
            'to' => $to,
            'starter_price' => $price,
            'ending_price' => (int)number_format($price + ($price * 0.25), 2),
            'estimated_pickup_time' => $pickup_time,
            'estimated_dropoff_time' => $dropoff_time,
            'shippingCostId' => self::$shippingCost->id
        ];
    }

    private static function calcCosts(Product $product, $customerID, $quantity, $to, $body, $isTown = true) {
        // Addresses
        $buyerAddress = self::getBuyerAddress($customerID);
        // Weight on Pounds
        $totalWeight = self::calcTotalWeight($product, $quantity);
        $totalVolume = self::extractVolume($product) * $quantity;
        $cart = $product->carts()->where('user_id', $customerID)->first();
        if (!$cart) {
            throw new HttpResponseException(response()->json(['message' => 'NOT_PRODUCT_IN_CART'], 404));
        }
        $isLocal = self::isLocalDelivery($buyerAddress);
        if ($isTown) {
            if (PedidosYaController::checkAvailability($body)) {
                $body['isTransferred'] = true;
                $pedidosYa = PedidosYaController::make($body);
                $price = 240 + $pedidosYa['delivery']['starter_price'];
                self::createShippingCost($pedidosYa, $cart, $body, $price);
            } else {
                $isLocal ? $price = 240.00 + 350.00 : $price = $to->zona->categoria->precio;
            }
        } else {
            if (PedidosYaController::checkAvailability($body)) {
                $pedidosYa = PedidosYaController::make($body);
                $price = 240 + $pedidosYa['delivery']['starter_price'];
            } else {
                $isLocal ? $price = 240.00 + 350.00 : $price = $to->categoria->precio;
            }
        }
        return self::calcExtraPrice($totalWeight, $totalVolume, $price);
    }

    private static function estimateDropOffTime($pickupTime, $isTown = true, $town = null, $isLocal = false) {
        // Tomar la fecha estimada de entrega a la paquetera
        $date = Carbon::createFromDate($pickupTime)->timezone('America/Santo_Domingo');
        // Si es una ciudad, calcular el tiempo de entrega a fecha actual + 5 días files
        // Si es un pueblo, calcular el tiempo de entrega al proximal día de disponibilidad
        if ($isLocal) $isTown = true;
        if ($isTown) {
            $isLocal ?
                $available_days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday'] :
                $available_days = array_map('ucfirst', json_decode($town->dias_de_entrega));
            // Si el día de recogida es un día de entrega, agrega un día
            if (in_array($date->englishDayOfWeek, $available_days)) {
                $date->addDay();
            }
            // Calcula el próximo día de entrega
            while (!in_array($date->englishDayOfWeek, $available_days)) {
                $date->addDay();
            }
        } else {
            $date->addRealDays(5);
            while ($date->isWeekend()) {
                $date->addDay();
            }
        }
        return $date->format('Y-m-d H:i:s');
    }
}