<?php
namespace App\Service;
use App\Entity\Product;
use App\Entity\Store;
use App\Repository\CountryRepository;
use App\Repository\FreightPriceRepository;
use App\Repository\PalletRepository;
use App\Repository\ProductRepository;
use App\Repository\ProvinceRepository;
use DVDoug\BoxPacker\Packer;
use DVDoug\BoxPacker\Test\TestBox;
use DVDoug\BoxPacker\Test\TestItem;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
*
*/
class CalculateService
{
/**
* @var PalletRepository
*/
private $palleteRepo;
/**
* @var ProductRepository
*/
private $productRepo;
/**
* @var Packer
*/
private $Packer;
/**
* @var FreightPriceRepository
*/
private $FPRepo;
/**
* @var CountryRepository
*/
private $countryRepo;
/**
* @var ProvinceRepository
*/
private $provinceRepo;
/**
* @param ContainerInterface $container
* @param PalletRepository $palletRepository
* @param ProductRepository $productRepository
* @param FreightPriceRepository $freightPriceRepository
* @param CountryRepository $countryRepository
* @param ProvinceRepository $provinceRepository
*/
public function __construct(PalletRepository $palletRepository, ProductRepository $productRepository,
FreightPriceRepository $freightPriceRepository, CountryRepository $countryRepository,
ProvinceRepository $provinceRepository)
{
$this->palleteRepo = $palletRepository;
$this->productRepo = $productRepository;
$this->FPRepo = $freightPriceRepository;
$this->countryRepo = $countryRepository;
$this->provinceRepo = $provinceRepository;
$this->Packer = new Packer();
$this->Packer->setMaxBoxesToBalanceWeight(1);
}
/**
* @param $cart
* @param Store $store
* @return array
*/
public function calculateShipment($cart, Store $store)
{
$params = [];
$origin_country = $this->countryRepo->findBy(['code' => $cart->rate->origin->country]);
$destination_country = $this->countryRepo->findBy(['code' => $cart->rate->destination->country]);
$origin_province = $this->provinceRepo->findBy(['code' => $cart->rate->origin->province]);
$destination_province = $this->provinceRepo->findBy(['code' => $cart->rate->destination->province]);
$params['origin_country'] = $origin_country;
$params['destination_country'] = $destination_country;
if ($origin_province) {
$params['origin_province'] = $origin_province;
}
if ($destination_province) {
$isDestination = $this->FPRepo->findBy(
[
'destination_country' => $destination_country,
'destination_province' => $destination_province,
'origin_country' => $origin_country
]
);
if ($isDestination) {
$params['destination_province'] = $destination_province;
}
}
// $params['store'] = $store;
$prices = $this->FPRepo->findBy($params);
foreach ($prices as $price) {
$pallet = $price->getPallete();
$this->Packer->addBox(new TestBox(
$pallet->getName(),
$pallet->getWidth() + 1,
$pallet->getLength() + 1,
$pallet->getHeight() + 1,
0,
$pallet->getWidth() + 0,
$pallet->getLength() + 0,
$pallet->getHeight() + 0,
$pallet->getWeight() + 0
));
}
// Products
$cartItems = [];
foreach ($cart->rate->items as $item) {
$product = $this->productRepo->findOneBy([
'product_id' => $item->product_id,
'variant_id' => $item->variant_id,
// 'store' => $store
]);
$cartItems[] = [
'quantity' => $item->quantity,
'product' => $product,
'position' => $product->getPosition() ?? 999
];
}
usort($cartItems, function ($a, $b) {
return $a['position'] <=> $b['position'];
});
$singlePallets = [];
foreach ($cartItems as $item) {
assert($item['product'] instanceof Product);
$product = $item['product'];
if($product->getIsSinglePalette()){
$cart = clone $cart;
$cart->rate->items = array_filter($cart->rate->items, function ($item) use ($product) {
return $item->product_id == $product->getProductId() && $item->variant_id == $product->getVariantId();
});
$cart->rate->items = array_map(function ($item) use ($product) {
$item->quantity = 1;
return $item;
}, $cart->rate->items);
for ($i = 0; $i < $item['quantity']; $i++){
$singlePallets[] = $this->calculateSinglePalet($cart, $store);
}
continue;
}
if (count($product->getSubProducts()) > 0) {
foreach ($product->getSubProducts() as $subProduct) {
$this->Packer->addItem(new TestItem(
$product->getName() . " --> " . $subProduct->getName(),
$subProduct->getWidth() + 0,
$subProduct->getLength() + 0,
$subProduct->getHeight() + 0,
$subProduct->getWeight() + 0,
$subProduct->getKeepFlat() ?? false
),
$item['quantity'] + 0
);
}
} else {
$this->Packer->addItem(new TestItem(
$product->getName() . "",
$product->getWidth() + 0,
$product->getLength() + 0,
$product->getHeight() + 0,
$product->getWeight() + 0,
$product->getKeepFlat() ?? false
),
$item['quantity'] + 0
);
}
}
$pallets = [];
$pallets[] = $this->Packer->pack();
$totalPallets = 0;
$total_shipping = 0;
$palletTypes = [
'count' => [],
'name' => [],
'typecount' => [],
'items' => [],
'order' => []
];
$boxIndex = 1;
$addedBoxIndex = 1;
$usedPalletes = [];
if (count($singlePallets) > 0) {
foreach ($singlePallets as $singlePallet) {
$pallets[] = $singlePallet;
}
}
foreach ($pallets as $packedBoxes) {
foreach ($packedBoxes as $packedBox) {
$palletType = $packedBox->getBox();
$pallet = $this->palleteRepo->findOneBy(['name' => $palletType->getReference(), 'store' => $store]);
$params['pallete'] = $pallet;
$params['store'] = $store;
$prices = $this->FPRepo->findBy($params);
if (!$prices || count($prices) < 1) {
continue;
}
if (!isset($usedPalletes[$pallet->getName()])) {
$usedPalletes[$pallet->getName()] = 0;
}
$usedPalletes[$pallet->getName()] += 1;
if ($pallet->getId() == 20) {
$total_shipping += $addedBoxIndex > 2 ? 50 / 100 * $prices[0]->getPrice() :
($addedBoxIndex > 1 ? 60 / 100 * $prices[0]->getPrice() :
$prices[0]->getPrice());
$addedBoxIndex++;
}
if (isset($palletTypes['typecount'][$pallet->getId()])) {
$palletTypes['typecount'][$pallet->getId()]++;
} else {
$palletTypes['typecount'][$pallet->getId()] = 1;
}
$palletTypes['order'][$boxIndex] = [
'pallet' => $pallet,
'prices' => $prices
];
$palletTypes['count'][$boxIndex] = $pallet->getId();
$palletTypes['name'][$pallet->getId()] = $pallet->getName();
$packedItems = $packedBox->getItems();
$palletTypes['items'][$boxIndex]['weight'] = 0;
foreach ($packedItems as $packedItem) {
$palletTypes['items'][$boxIndex]['name'][] = $packedItem->getItem()->getDescription();
$palletTypes['items'][$boxIndex]['weight'] += $packedItem->getItem()->getWeight();
}
$boxIndex++;
$totalPallets++;
}
}
if (count($palletTypes['order'])) {
foreach ($palletTypes['order'] as $boxIndex => $palletData) {
if ($palletData['pallet']->getId() != 20) {
$total_shipping += $addedBoxIndex > 2 ? 50 / 100 * $palletData['prices'][0]->getPrice() :
($addedBoxIndex > 1 ? 60 / 100 * $palletData['prices'][0]->getPrice() :
$palletData['prices'][0]->getPrice());
$addedBoxIndex++;
}
}
}
$description = " ( ";
foreach ($palletTypes['typecount'] as $key => $value) {
$description .= $value . " - " . $palletTypes['name'][$key];
if (end($palletTypes['typecount']) != $key) {
$description .= ", ";
}
}
$description .= " ) ";
$totalPrice = round((($total_shipping * 1.1) + 25) * 100);
if ($store->getStoreId() == '55440933032') {
$totalPrice = round($total_shipping * 100);
}
return [
"rates" => [
"rates" => [
[
'service_name' => "Calculating Shipping Rates",
'service_code' => "PPAPP",
'total_price' => $totalPrice,
'description' => " Total Pallets : $totalPallets \n $description",
'currency' => $cart->rate->currency,
'min_delivery_date' => date("Y-m-d H:i:s P"),
'max_delivery_date' => date("Y-m-d H:i:s P")
]
]
],
"content" => $palletTypes['items']
];
}
public function calculateSinglePalet($cart, Store $store)
{
$packer = new Packer();
$packer->setMaxBoxesToBalanceWeight(1);
$params = [];
$origin_country = $this->countryRepo->findBy(['code' => $cart->rate->origin->country]);
$destination_country = $this->countryRepo->findBy(['code' => $cart->rate->destination->country]);
$origin_province = $this->provinceRepo->findBy(['code' => $cart->rate->origin->province]);
$destination_province = $this->provinceRepo->findBy(['code' => $cart->rate->destination->province]);
$params['origin_country'] = $origin_country;
$params['destination_country'] = $destination_country;
if ($origin_province) {
$params['origin_province'] = $origin_province;
}
if ($destination_province) {
$isDestination = $this->FPRepo->findBy(
[
'destination_country' => $destination_country,
'destination_province' => $destination_province,
'origin_country' => $origin_country
]
);
if ($isDestination) {
$params['destination_province'] = $destination_province;
}
}
// $params['store'] = $store;
$prices = $this->FPRepo->findBy($params);
foreach ($prices as $price) {
$pallet = $price->getPallete();
$packer->addBox(new TestBox(
$pallet->getName(),
$pallet->getWidth() + 1,
$pallet->getLength() + 1,
$pallet->getHeight() + 1,
0,
$pallet->getWidth() + 0,
$pallet->getLength() + 0,
$pallet->getHeight() + 0,
$pallet->getWeight() + 0
));
}
// Products
$cartItems = [];
foreach ($cart->rate->items as $item) {
$product = $this->productRepo->findOneBy([
'product_id' => $item->product_id,
'variant_id' => $item->variant_id,
// 'store' => $store
]);
$cartItems[] = [
'quantity' => $item->quantity,
'product' => $product,
'position' => $product->getPosition() ?? 999
];
}
usort($cartItems, function ($a, $b) {
return $a['position'] <=> $b['position'];
});
foreach ($cartItems as $item) {
$product = $item['product'];
if (count($product->getSubProducts()) > 0) {
foreach ($product->getSubProducts() as $subProduct) {
$packer->addItem(new TestItem(
$product->getName() . " --> " . $subProduct->getName(),
$subProduct->getWidth() + 0,
$subProduct->getLength() + 0,
$subProduct->getHeight() + 0,
$subProduct->getWeight() + 0,
$subProduct->getKeepFlat() ?? false
),
$item['quantity'] + 0
);
}
} else {
$packer->addItem(new TestItem(
$product->getName() . "",
$product->getWidth() + 0,
$product->getLength() + 0,
$product->getHeight() + 0,
$product->getWeight() + 0,
$subProduct->getKeepFlat() ?? false
),
$item['quantity'] + 0
);
}
}
return $packer->pack();
}
}