quivers-8.x-1.x-dev/src/QuiversService.php
src/QuiversService.php
<?php
namespace Drupal\quivers;
use Exception;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Logger\LoggerChannelFactoryInterface;
use Drupal\Core\TypedData\Exception\MissingDataException;
use Drupal\profile\Entity\ProfileInterface;
use Drupal\commerce_order\Entity\OrderInterface;
use Drupal\commerce_order\Entity\OrderItemInterface;
use Drupal\commerce_tax\Event\CustomerProfileEvent;
use Drupal\commerce_tax\Event\TaxEvents;
use GuzzleHttp\Exception\ClientException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
/**
* Quivers Service.
*/
class QuiversService {
/**
* The Quivers configuration.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $quiversConfig;
/**
* The Quivers Tax configuration.
*
* @var \Drupal\Core\Config\ImmutableConfig
*/
protected $quiversTaxConfig;
/**
* The client.
*
* @var \GuzzleHttp\Client
*/
protected $quiversClient;
/**
* The event dispatcher.
*
* @var \Symfony\Component\EventDispatcher\EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* The logger.
*
* @var \Drupal\Core\Logger\LoggerChannelInterface
*/
protected $logger;
protected $logTracking;
/**
* Constructs a new QuiversTax object.
*
* @param \Drupal\quivers\ClientFactory $client_factory
* The client.
* @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
* The configuration factory.
* @param \Symfony\Component\EventDispatcher\EventDispatcherInterface $event_dispatcher
* The event dispatcher.
* @param \Drupal\Core\Logger\LoggerChannelFactoryInterface $logger_factory
* The logger.
*/
public function __construct(ClientFactory $client_factory, ConfigFactoryInterface $config_factory, EventDispatcherInterface $event_dispatcher, LoggerChannelFactoryInterface $logger_factory, LogTracking $log_tracking) {
$this->quiversConfig = $config_factory->get('quivers.settings');
$this->quiversTaxConfig = $config_factory->get('quivers.tax_settings');
$this->quiversClient = $client_factory->createInstance($this->quiversConfig->get());
$this->eventDispatcher = $event_dispatcher;
$this->logger = $logger_factory->get('quivers');
$this->logTracking = $log_tracking;
}
public function splitBills($totalAmount, int $ways) {
$splittedAmounts = [];
// divide total amount into ways
$amountPerItem = round($totalAmount/$ways, 2);
// splitted amounts for each way
for($i=0; $i<$ways; $i++) {
$splittedAmounts[$i] = $amountPerItem;
}
// check difference of given total amount and total splitted amount
$amountDiff = round($totalAmount - array_sum($splittedAmounts), 2);
// if diff is 0 return splitted amounts
if($amountDiff==0) return $splittedAmounts;
$iterations = abs((int) ($amountDiff * 100));
$isAddition = $amountDiff > 0;
// add or subtract 0.01 to splitted amounts to get to the total amount
if($isAddition) {
for ($j=0; $j<$iterations; $j++) {
$splittedAmounts[$j] = round((float) ($splittedAmounts[$j] + ($isAddition ? 0.01 : -0.01)), 2);
}
}else {
$length = count($splittedAmounts) - 1;
for($j=$length; $j > ($length - $iterations); $j--) {
$splittedAmounts[$j] = round((float) ($splittedAmounts[$j] + ($isAddition ? 0.01 : -0.01)), 2);
}
}
return $splittedAmounts;
}
public function getLineItemsDiscount($order, $orderLevelDiscount=0, $discountPercentage=0)
{
$per_item_discount = [];
$subTotalPrice = $order->getSubtotalPrice()->getNumber();
$items = $order->getItems();
if($orderLevelDiscount > 0) $discountPercentage = ($orderLevelDiscount/$subTotalPrice);
elseif(!$discountPercentage) return [];
$drupalDiscount = $subTotalPrice * $discountPercentage;
$totalItemDiscount = 0;
// divide discounts
foreach($items as $item) {
$itemPrice = $item->getUnitPrice()->getNumber() * $item->getQuantity();
$itemDiscount = $itemPrice * $discountPercentage;
$per_item_discount[$item->uuid()] = round($itemDiscount, 2);
$totalItemDiscount = $totalItemDiscount + $per_item_discount[$item->uuid()];
}
$discountDiff= round($totalItemDiscount- $drupalDiscount, 2);
foreach($items as $item) {
if (!$discountDiff) {
break;
}
$per_item_discount[$item->uuid()] -= 0.01;
$discountDiff = round(($discountDiff - 0.01),2);
}
return $per_item_discount;
}
public function processOrderDiscounts($order) {
// $rounder = \Drupal::service('commerce_price.rounder');
$per_item_discount = [];
$coupons = $order->get('coupons')->referencedEntities();
$promotion = count($coupons) ? $coupons[0]->getPromotion() : null;
$couponType = $promotion ? $promotion->getOffer()->getEntityTypeId() : null;
if($couponType && (string)$couponType==='commerce_order') {
$offer = $promotion->get('offer')->first()->getValue();
$offerType = $offer['target_plugin_id'];
$target_plugin_configuration = $offer['target_plugin_configuration'];
if($offerType!='order_buy_x_get_y') {
$orderLevelDiscount = 0;
$discountPercentage = 0;
switch ($offer['target_plugin_id']) {
case 'order_fixed_amount_off':
$amountOff = $target_plugin_configuration['amount']['number'];
$orderSubtotal = $order->getSubtotalPrice();
if($amountOff > $orderSubtotal->getNumber()) {
$amountOff = $orderSubtotal->getNumber();
}
$orderLevelDiscount = $amountOff;
break;
case 'order_percentage_off':
$percentageOff = $target_plugin_configuration['percentage'];
$discountPercentage = $percentageOff;
break;
}
if($orderLevelDiscount || $discountPercentage) {
// split discounts per applicable items
$per_item_discount = $this->getLineItemsDiscount($order, $orderLevelDiscount, $discountPercentage);
}
}
}
$allOrderItems = [];
$this->container = \Drupal::getContainer();
$resolver = $this->container->get('commerce_pricelist.price_resolver');
$context = new \Drupal\commerce\Context($order->getCustomer(), $order->getStore());
foreach($order->getItems() as $order_item) {
$productPrice = $order_item->getPurchasedEntity()->getPrice()->getNumber();
$resolved_price = $resolver->resolve($order_item->getPurchasedEntity(), 1, $context);
$productPrice = $resolved_price ? $resolved_price->getNumber() : $productPrice;
$unitPrice = $order_item->getUnitPrice()->getNumber();
$itemDiscount = 0;
if($productPrice - $unitPrice > 0) {
$itemDiscount = $productPrice - $unitPrice;
}
if($couponType==='commerce_order_item') {
$offer = $promotion->getOffer();
$offer_conditions = new \Drupal\commerce\ConditionGroup($offer->getConditions(), $offer->getConditionOperator());
if($offer_conditions->evaluate($order_item)) {
$offer = $promotion->get('offer')->first()->getValue();
$target_plugin_configuration = $offer['target_plugin_configuration'];
if(!$target_plugin_configuration['display_inclusive']) {
switch ($offer['target_plugin_id']) {
case 'order_item_fixed_amount_off':
$amountOff = $target_plugin_configuration['amount']['number'];
// $itemDiscount = $rounder->round($amountOff);
if($amountOff > $order_item->getUnitPrice()->getNumber()) {
$amountOff = $order_item->getUnitPrice()->getNumber();
}
$itemDiscount += $amountOff;
break;
case 'order_item_percentage_off':
$percentageOff = $target_plugin_configuration['percentage'];
$product_price = $order_item->getPurchasedEntity()->getPrice();
$amountOff = $product_price->multiply($percentageOff);
$itemDiscount += $amountOff->getNumber();
if($amountOff > $order_item->getUnitPrice()->getNumber()) {
$amountOff = $order_item->getUnitPrice()->getNumber();
}
break;
}
}
}
}
if(count($per_item_discount) > 0) {
$lineItemDiscount = isset($per_item_discount[$order_item->uuid()]) ? $per_item_discount[$order_item->uuid()] : 0;
}
$order_item->productPrice = round($productPrice, 2);
$order_item->perLineItemDiscount = isset($lineItemDiscount) ? $lineItemDiscount : 0;
$order_item->discountAmount = round($itemDiscount, 2);
$allOrderItems[] = $order_item;
}
return $allOrderItems;
}
/**
* Get tax from Quivers Validate API.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* OrderInterface object.
*
* @return array
* Array of Order Item Taxes.
*
* @throws Exception
*/
public function calculateValidateTax(OrderInterface $order) {
$config = $this->quiversConfig->get();
$debug_mode = $config["debug_mode"];
$startTime = microtime(true);
$tax_response = [];
$user_profile = NULL;
$order_shipments = [];
$request_data = [
"marketplaceId" => NULL,
"shippingAddress" => [],
"items" => [],
"customer" => [],
];
$Email = $order->getEmail();
$has_shipments = $order->hasField('shipments') && !$order->get('shipments')->isEmpty();
if ($has_shipments) {
$order_shipment_amt = 0;
foreach ($order->get('shipments')->referencedEntities() as $shipment) {
$amt = $shipment->getAmount();
if ($amt !== NULL){
$order_shipment_amt = $order_shipment_amt + $amt->getNumber();
}
}
$splitted_order_shipments = $order_shipment_amt ? $this->splitBills($order_shipment_amt, count($order->getItems())) : [];
$itemCounter = 0;
foreach ($order->getItems() as $order_item) {
// $order_item_shipment_amt = $order_shipment_amt / (int) $order_item->getQuantity();
// $order_item_shipment_amt = $order_shipment_amt / (int) count($order->getItems());
$order_shipments[$order_item->uuid()] = isset($splitted_order_shipments[$itemCounter]) ? $splitted_order_shipments[$itemCounter] : 0;
$itemCounter++;
}
}
// process discounts on order items
$allOrderItems = $this->processOrderDiscounts($order);
// iterate on allOrderItems and prepare validate request api postdata
foreach($allOrderItems as $order_item) {
$splitted_discounts = [];
if($order_item->perLineItemDiscount) {
$splitted_discounts = $this->splitBills($order_item->perLineItemDiscount, $order_item->getQuantity());
}
// divide shipments into quantity
$splitted_shipments = [];
if(isset($order_shipments[$order_item->uuid()]) && $order_shipments[$order_item->uuid()] > 0) {
$splitted_shipments = $this->splitBills($order_shipments[$order_item->uuid()], $order_item->getQuantity());
}
$user_profile = $this->resolveCustomerProfile($order_item);
// If no profile resolved yet, no need for any Tax calculation.
if (!$user_profile) {
continue;
}
for($i=0; $i<$order_item->getQuantity(); $i++) {
$quantity_discount = $order_item->discountAmount;
if(count($splitted_discounts) > 0) $quantity_discount += $splitted_discounts[$i];
// $validate_request_item_data = self::prepareValidateRequestItemData($order_item, $order_shipments);
$quantity_shipment = isset($splitted_shipments[$i]) ? $splitted_shipments[$i] : 0;
$validate_request_item_data = self::prepareValidateRequestItemData($order_item, $quantity_shipment);
$order_coupons = $order->get('coupons')->referencedEntities();
if(count($order_coupons) > 0) {
$couponCode = $order_coupons[0]->get('code')->getValue()[0]['value'];
$promotion = $order_coupons[0]->getPromotion();
$offer = $promotion->get('offer')->first()->getValue();
$offerType = $offer['target_plugin_id'];
if($offerType==='order_buy_x_get_y') {
$order_buy_x_get_y = 1;
}else {
$itemUnitPrice = $order_item->productPrice;
$order_buy_x_get_y = 0;
}
}else {
$couponCode = '';
$itemUnitPrice = $order_item->productPrice;
$order_buy_x_get_y = 0;
}
if($order_buy_x_get_y==0) {
$validate_request_item_data['pricing']['unitPrice'] = $order_item->productPrice;
$discount_obj = [
'code' => $couponCode,
'name' => $couponCode,
'description' => 'discount',
'amount' => $quantity_discount ? (0 - round($quantity_discount, 2)) : 0
];
$validate_request_item_data['pricing']['discounts'][] = $discount_obj;
}
/* start code add taxCode in request of validate APi */
$product_variation = $order_item->getPurchasedEntity();
if ($debug_mode){
$this->logTracking->debug_mode_on($debug_mode,'calculateValidateTax','PRODUCT VARIATION DATA',$Email,null,null,$product_variation);
}
$product_id = $product_variation->product_id->getString();
$product = \Drupal\commerce_product\Entity\Product::load((int)$product_id);
if ($debug_mode){
$this->logTracking->debug_mode_on($debug_mode,'calculateValidateTax','PRODUCT DATA',$Email,null,null,$product);
}
try{
if ($product !== NULL){
$taxcodes = $product->get("taxcode")->getValue();
foreach($taxcodes as $key=>$taxcode){
if( $taxcodes === NULL){
continue;
}
$taxcode_value= $taxcode['value'];
}
}
}
catch(Exception $e) {
$this->logTracking->debug_mode_on($debug_mode,'In catch Product not found',$e->getMessage(),$Email,null,null,null);
return "No product found.If the issue still persists,please contact 'enterprise@quivers.com' for further assistance.";
}
$validate_request_item_data['product']['taxCode'] = $taxcode_value;
$request_data['items'][] = $validate_request_item_data;
}
}
// previous code
// foreach ($order->getItems() as $order_item) {
// $user_profile = $this->resolveCustomerProfile($order_item);
// // If no profile resolved yet, no need for any Tax calculation.
// if (!$user_profile) {
// continue;
// }
// $validate_request_item_data = self::prepareValidateRequestItemData($order_item, $order_shipments);
// $request_data['items'][] = $validate_request_item_data;
// }
// If no items are ready for Tax calculation. return [].
if (empty($request_data["items"])) {
$this->logTracking->debug_mode_on($debug_mode,'calculateValidateTax','Request Data Item Empty',$Email,null,null,$tax_response);
return $tax_response;
}
// Get Marketplace Id using Order Store UUID.
$marketplace_id = self::getMarketPlaceId($order);
if ($debug_mode){
$this->logTracking->debug_mode_on($debug_mode,'calculateValidateTax','Marketplace Id',$Email,null,null,$marketplace_id);
}
if ($marketplace_id === NULL) {
$this->logTracking->debug_mode_on($debug_mode,'calculateValidateTax','Marketplace Id Null',$Email,null,null,$tax_response);
return $tax_response;
}
$request_data['marketplaceId'] = $marketplace_id;
$address_data = self::getShippingAddressData($user_profile, $order);
$this->logTracking->debug_mode_on($debug_mode,'calculateValidateTax','Address Data Passed in API ',$Email,null,null,$address_data);
if (empty($address_data)) {
$this->logTracking->debug_mode_on($debug_mode,'calculateValidateTax','Address Data is Null ',$Email,null,null,$tax_response);
return $tax_response;
}
$request_data['shippingAddress'] = $address_data['address'];
$customer_data = $address_data['customer'];
$customer_data['email'] = $order->getEmail();
$request_data['customer'] = $customer_data;
$this->logTracking->session_start($request_data, gmdate('r', $startTime)."UTC");
try {
$response = $this->quiversClient->post('customerOrders/validate',
['json' => $request_data]
);
$response_data = Json::decode($response->getBody()->getContents());
$tax_response = self::formatValidateResponse($response_data);
$config = $this->quiversConfig->get();
$baseUri = $config["api_mode"]=='production'? 'https://api.quivers.com/v1/':'https://api.quiversdemo.com/v1/';
$request = ["base url"=>$baseUri, "Endpoint"=>'customerOrders/validate', 'Data'=>$request_data];
$endTime = microtime(true);
$order_detail = ["tax_data"=>$request_data, "Response"=>$response_data];
$statement_descriptor = $response_data['result']['statementDescriptor'];
if(strlen($statement_descriptor) > 10){
$statement_descriptor = substr($statement_descriptor, 0, 10);
}
$this->logTracking->statement_descriptor($statement_descriptor);
$order->setData('field_statement_descriptor', $statement_descriptor);
$this->logTracking->order_data($order->getData('field_statement_descriptor'));
$this->logTracking->validate_api_call($request, $response_data, gmdate('r', $startTime)."UTC", gmdate('r', $endTime)."UTC");
$this->logTracking->session_end($order_detail, gmdate('r', $endTime)."UTC");
}
catch (ClientException $e) {
$this->logTracking->debug_mode_on($debug_mode,'validate request fail',null,$Email,null,$e->getMessage(),null);
$this->logger->notice($e->getMessage());
throw new Exception($e->getMessage());
}
catch (\Exception $e) {
$this->logTracking->debug_mode_on($debug_mode,'validate request fail Execption',null,$Email,null,$e->getMessage(),null);
$this->logger->notice($e->getMessage());
throw new Exception($e->getMessage());
}
$data = ['tax' =>$response_data['result']['totals'] ,'tax_response'=> $tax_response];
$this->logTracking->debug_mode_on($debug_mode,'validate Response',null,$Email,null,$data,null);
return $data;
}
/**
* Prepare Quivers Validate API Request data for given Order Item.
*
* @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
* OrderItemInterface object.
*
* @return array
* Quivers Validate API Request LineItem data.
*/
// protected function prepareValidateRequestItemData(OrderItemInterface $order_item, array $order_shipments) {
protected function prepareValidateRequestItemData(OrderItemInterface $order_item, $quantity_shipment) {
$order_item_unit_price = (float) $order_item->getUnitPrice()->getNumber();
$order_item_shipping_fee = $quantity_shipment;
$line_item = [
'product' => [
'name' => $order_item->getTitle(),
'variant' => [
"name" => $order_item->getTitle(),
"refId" => $order_item->uuid(),
],
],
// 'quantity' => (int) $order_item->getQuantity(),
'quantity' => 1,
'pricing' => [
'unitPrice' => $order_item_unit_price,
'shippingFees' => [[
'name' => 'Shipping',
'amount' => (float) $order_item_shipping_fee,
]],
],
];
return $line_item;
}
/**
* Get Address Data for Quivers Validate Tax API.
*
* @param \Drupal\profile\Entity\ProfileInterface $profile
* ProfileInterface object.
*
* @return array
* Quivers Validate API Request Address data.
*/
protected function getShippingAddressData(ProfileInterface $profile, OrderInterface $order) {
$address_data = [];
try {
$Email = $order->getEmail();
$address = null;
$blockinfo = "";
$order_profiles = $order->collectProfiles();
if (isset($order_profiles['shipping'])){
$address = $order_profiles['shipping']->get('address')->first();
if(!empty($address->getAdministrativeArea())){
$order_region_code = $address->getAdministrativeArea();
}
$blockinfo = "order_profiles";
}
elseif (isset($profile)){// profile check.
/** @var \Drupal\address\AddressInterface $address */
$address = $profile->get('address')->first();
if(isset($address)){
if($address->getAdministrativeArea()!=null){
$order_region_code = $address->getAdministrativeArea();
}
}
$blockinfo = "profiles";
}
elseif($address==null){
foreach ($order->getItems() as $order_item) {
$user_profile = $this->resolveCustomerProfile($order_item);
try {
/** @var \Drupal\address\AddressInterface $address */
if(isset($user_profile)){
$address = $user_profile->get('address')->first();
if($address->getAdministrativeArea()){
$order_region_code = $address->getAdministrativeArea();
}
$blockinfo = "user_profile";
}
}
catch (MissingDataException $e) {
$this->logTracking->debug_mode_on(TRUE,'MissingDataException_resolveCustomerProfile','In Catch Address not Found from user profile',$Email,null,$order->id(),$e->getMessage());
$this->logger->error("Unable to access Address instance." . $e->getMessage());
}
}
}
else{
$shipping_profile = QuiversService::checkshippingDetailsData($order);
if(isset($shipping_profile)){
$address= $shipping_profile->get('address')->first();
$blockinfo = "shipping_profile";
if(!empty($address->getAdministrativeArea())){
$order_region_code = $address->getAdministrativeArea();
}
}
}
$this->logTracking->shipping_address($address);
}
catch (MissingDataException $e) {
$this->logger->error("Unable to access Address instance." . $e->getMessage());
$this->logTracking->debug_mode_on(TRUE,'MissingDataException_getShippingAddressData','In catch Address Return Error',$Email,$order->id(),$address_data,$e->getMessage());
return $address_data;
}
$order_country_code = $address->getCountryCode();
$order_region_code = $address->getAdministrativeArea();
$order_region_name = $address->getLocality();
if (!($order_region_name || $order_region_code)) {
// If not Region & Code, can not calculate Tax.
$this->logger->notice("Order Region Code and Region Name are NULL.");
return $address_data;
}
if (!($order_region_code && strlen($order_region_code) <= 3)) {
// We don't have correct Region Code, get Code from Quivers.
$order_region_code = self::getQuiversRegionCode($order_country_code, $order_region_name);
}
if (!$order_region_code) {
$order_region_code = 'N/A';
}
$address_data = [
'address' => [
'line1' => ($address->getAddressLine1() === NULL) ? "" : $address->getAddressLine1(),
'line2' => ($address->getAddressLine2() === NULL) ? "" : $address->getAddressLine2(),
'city' => ($address->getLocality() === NULL) ? "" : $address->getLocality(),
'postCode' => ($address->getPostalCode() === NULL) ? "" : $address->getPostalCode(),
'region' => $order_region_code,
'country' => $address->getCountryCode(),
],
'customer' => [
'firstname' => ($address->getGivenName() === NULL) ? "" : $address->getGivenName(),
'lastname' => ($address->getFamilyName() === NULL) ? "" : $address->getFamilyName(),
]
];
$this->logTracking->debug_mode_on(TRUE,'Final Address Details',$blockinfo,$Email,$order->id(),null,$address_data);
return $address_data;
}
/**
* Format Quivers Validate API response.
*
* @param array $validate_tax_data
* Response from Quivers Validate API.
*
* @return array
* Array of Order Item wise tax, NULL.
*/
protected function formatValidateResponse(array $validate_tax_data) {
$order_item_taxes = [];
if (empty($validate_tax_data['result']) || empty($validate_tax_data['result']['items'])) {
return $order_item_taxes;
}
foreach ($validate_tax_data['result']['items'] as $order_item_tax_data) {
$order_item_tax = 0;
foreach ($order_item_tax_data['pricing']['taxes'] as $validate_tax) {
$order_item_tax = $order_item_tax + $validate_tax['amount'];
}
if(isset($order_item_taxes[$order_item_tax_data['variantRefId']])) {
$order_item_taxes[$order_item_tax_data['variantRefId']] += $order_item_tax;
}else {
$order_item_taxes[$order_item_tax_data['variantRefId']] = $order_item_tax;
}
// $order_item_taxes[$order_item_tax_data['variantRefId']] = $order_item_tax;
}
return $order_item_taxes;
}
/**
* Returns Order Item Taxes from Quivers Countries API.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* OrderInterface object.
*
* @return array
* Array of Order Item taxes.
*/
public function calculateCountryTax(OrderInterface $order) {
$startTime = microtime(true);
$tax_response = [];
$address = NULL;
$config = $this->quiversConfig->get();
$Email = $order->getEmail();
$allOrderItems = $this->processOrderDiscounts($order);
$itemShipping=[];
$has_shipments = $order->hasField('shipments') && !$order->get('shipments')->isEmpty();
if ($has_shipments) {
$order_shipment_amt = 0;
foreach ($order->get('shipments')->referencedEntities() as $shipment) {
$amt = $shipment->getAmount();
if ($amt !== NULL){
$order_shipment_amt = $order_shipment_amt + $amt->getNumber();
}
}
$splitted_order_shipments = $order_shipment_amt ? $this->splitBills($order_shipment_amt, count($order->getItems())) : [];
$itemCounter = 0;
foreach ($order->getItems() as $order_item) {
$order_shipments[$order_item->uuid()] = isset($splitted_order_shipments[$itemCounter]) ? $splitted_order_shipments[$itemCounter] : 0;
$itemCounter++;
}
}
foreach($allOrderItems as $order_item) {
$splitted_shipments = [];
if(isset($order_shipments[$order_item->uuid()]) && $order_shipments[$order_item->uuid()] > 0) {
$splitted_shipments = $this->splitBills($order_shipments[$order_item->uuid()], $order_item->getQuantity());
}
for($i=0; $i<$order_item->getQuantity(); $i++) {
$quantity_shipment = isset($splitted_shipments[$i]) ? $splitted_shipments[$i] : 0;
$validate_request_item_data = self::prepareValidateRequestItemData($order_item, $quantity_shipment);
$itemShipping[$validate_request_item_data['product']['variant']['refId']]=$validate_request_item_data['pricing']['shippingFees'][0]['amount'];
}
}
foreach ($order->getItems() as $order_item) {
$user_profile = $this->resolveCustomerProfile($order_item);
// If no profile resolved yet, no need for any Tax calculation.
if (!$user_profile) {
continue;
}
try {
/** @var \Drupal\address\AddressInterface $address */
$address = $user_profile->get('address')->first();
}
catch (MissingDataException $e) {
$this->logger->error("Unable to access Address instance." . $e->getMessage());
return $tax_response;
}
if ($address) {
break;
}
}
// If no items are ready for Tax calculation. return [].
if ($address === NULL) {
return $tax_response;
}
$order_country_code = $address->getCountryCode();
$order_region_code = $address->getAdministrativeArea();
$order_region_name = $address->getLocality();
$order_data = ["Country code"=>$order_country_code, "Region code"=>$order_region_code, "Region Name"=>$order_region_name];
$this->logTracking->session_start(["Tax Data"=>$order_data], gmdate('r', $startTime)."UTC");
$countries_response_data = self::getQuiversCountries();
// If API call unable to return Countries list.
if (empty($countries_response_data)) {
return $tax_response;
}
$country_max_tax_rate = NULL;
foreach ($countries_response_data['result'] as $value) {
if ($value['abbreviations']['two'] === $order_country_code) {
foreach ($value['regions'] as $region_value) {
if (strcasecmp($region_value['abbreviation'], $order_region_code) == 0) {
$isShippedTaxed=$region_value['isShippingTaxed'];
$country_max_tax_rate = (float) $region_value['maxTaxRate'];
break;
}
if (strcasecmp($region_value['name'], $order_region_name) == 0) {
$country_max_tax_rate = (float) $region_value['maxTaxRate'];
break;
}
}
// Quivers supports "N/A" regions for some countries.
if (!$country_max_tax_rate && array_key_exists('0', $value['regions'])) {
$country_max_tax_rate = (float) $value['regions']["0"]["maxTaxRate"];
}
}
if ($country_max_tax_rate) {
break;
}
}
if ($country_max_tax_rate === NULL) {
$this->logger->error("Region not supported with Quivers - " . (string) $order_region_code . "|" . (string) $order_country_code);
return $tax_response;
}
$tax = 0;
foreach ($order->getItems() as $order_item) {
$tax += $order_item->getAdjustedUnitPrice()->getNumber() * $country_max_tax_rate * (int) $order_item->getQuantity();
$itemShippingFee = $itemShipping[$order_item->uuid()];
if(json_encode($isShippedTaxed) =='true'){
$tax_response[$order_item->uuid()] = (((float) $order_item->getAdjustedUnitPrice()->getNumber() + $itemShippingFee ) * (int) $order_item->getQuantity() )* $country_max_tax_rate;
}
elseif(json_encode($isShippedTaxed) =='false'){
$tax_response[$order_item->uuid()] = (float) $order_item->getAdjustedUnitPrice()->getNumber() * $country_max_tax_rate * (int) $order_item->getQuantity();
}
}
$endTime = microtime(true);
$this->logTracking->session_end(["Tax Data"=>$order_data, "Response"=>$countries_response_data], gmdate('r', $endTime)."UTC");
$data = ['tax' =>$tax ,'tax_response'=> $tax_response];
return $data;
}
/**
* Quivers Countries API with Region Details.
*
* @return array
* List of Countries with Region details.
*/
protected function getQuiversCountries() {
$startTime = microtime(true);
$countries = [];
try {
$response = $this->quiversClient->get('countries');
$countries = Json::decode($response->getBody()->getContents());
$config = $this->quiversConfig->get();
$baseUri = $config["api_mode"]=='production'? 'https://api.quivers.com/v1/':'https://api.quiversdemo.com/v1/';
$request = ["base url"=>$baseUri, "Endpoint"=>'countries'];
$endTime = microtime(true);
$this->logTracking->countries_api_call($request, $countries, gmdate('r', $startTime)."UTC", gmdate('r', $endTime)."UTC");
}
catch (ClientException $e) {
$this->logger->notice($e->getMessage());
}
catch (\Exception $e) {
$this->logger->notice($e->getMessage());
}
return $countries;
}
/**
* Get Region code using Region Name from Quivers.
*
* @param string $country_code
* String country name.
* @param string $region_name
* String region name.
*
* @return string
* Two letter Region Code.
*/
protected function getQuiversRegionCode($country_code, $region_name) {
$quivers_countries_response_data = self::getQuiversCountries();
$region_code = NULL;
if (empty($quivers_countries_response_data)) {
return $region_code;
}
foreach ($quivers_countries_response_data['result'] as $value) {
if ($value['abbreviations']['two'] == $country_code) {
foreach ($value['regions'] as $region_value) {
if (strcasecmp($region_value['name'], $region_name) == 0) {
$region_code = $region_value['abbreviation'];
break;
}
}
// Quivers supports "N/A" regions for some countries.
if (!$region_code && array_key_exists('0', $value['regions'])) {
return $value['regions']["0"]["abbreviation"];
}
}
if ($region_code) {
break;
}
}
return $region_code;
}
/**
* Get Quivers MarketplaceID from 'Quivers Settings'.
*
* @param \Drupal\commerce_order\Entity\OrderInterface $order
* OrderInterface object.
*
* @return string|null
* Quivers MarketplaceID or NULL.
*/
protected function getMarketPlaceId(OrderInterface $order) {
$marketplace_id = NULL;
$marketplace_mappings =(array) json_decode($this->quiversTaxConfig->get('marketplaces'));
if (!$marketplace_mappings) {
$this->logger->error("Quivers Marketplaces are NOT configured");
return $marketplace_id;
}
$order_store_id = $order->getStore()->uuid();
// Get quivers marketplace id for order store uuid.
foreach ($marketplace_mappings as $mapping) {
$mapping =(array)$mapping;
if ($mapping['store_id'] === $order_store_id) {
$marketplace_id = $mapping['quivers_marketplace_id'];
break;
}
}
if ($marketplace_id === "") {
// If somehow Marketplace is not configured
// for the store correctly and Quivers Tax enabled.
$this->logger->error("Quivers Marketplace NOT configured for store id - " . $order_store_id);
$marketplace_id = NULL;
}
return $marketplace_id;
}
/**
* Stolen from TaxTypeBase::resolveCustomerProfile().
*
* @param \Drupal\commerce_order\Entity\OrderItemInterface $order_item
* The order item.
*
* @return \Drupal\profile\Entity\ProfileInterface|null
* The customer profile, or NULL if not yet known.
*/
protected function resolveCustomerProfile(OrderItemInterface $order_item) {
$order = $order_item->getOrder();
$config = $this->quiversConfig->get();
$debug_mode = $config["debug_mode"];
$customer_profile = $order->getBillingProfile();
$Email = $order->getEmail();
if ($debug_mode){
$this->logTracking->debug_mode_on($debug_mode,'resolveCustomerProfile','GET CUSTOMER PROFILE',$Email,null,null,$customer_profile);
}
// A shipping profile is preferred, when available.
$event = new CustomerProfileEvent($customer_profile, $order_item);
$this->eventDispatcher->dispatch(TaxEvents::CUSTOMER_PROFILE, $event);
$customer_profile = $event->getCustomerProfile();
return $customer_profile;
}
public static function checkshippingDetailsData(OrderInterface $order) {
if(!empty($order->shipments)){
if(!empty($order->shipments->first()->entity)){
$shippement = $order->shipments->first()->entity;
$shipping_profile = $shippement->shipping_profile->first()->entity;
}
}
return $shipping_profile;
}
}
