File: D:/HostingSpaces/SBogers10/topswtw.komma.pro/app/KommaApp/Shop/Orders/OrderService.php
<?php
namespace KommaApp\Shop\Orders;
use Carbon\Carbon;
use Illuminate\Support\Facades\Config;
use Komma\Kms\Shipments\ShipmentService;
use KommaApp\Shop\Checkout\CheckoutSession\CheckoutSession;
use KommaApp\Shop\Customers\Customer;
use KommaApp\Shop\Customers\CustomerService;
use KommaApp\Shop\FormValidation\CheckoutForm;
use KommaApp\Shop\Mailers\CustomerMailer;
class OrderService
{
/**
* @var Order
*/
protected $order;
/**
* @var CheckoutForm
*/
protected $checkoutForm;
/**
* @var CheckoutSession
*/
protected $checkoutSession;
/**
* @var CustomerService
*/
protected $customerService;
/**
* @var OrderProduct
*/
private $orderProduct;
/**
* @var CustomerMailer
*/
private $customerMailer;
/**
* @var OrderToken
*/
private $orderToken;
/**
* @var OrderRepository
*/
private $orderRepository;
/**
* @param CheckoutSession $checkoutSession
* @param CheckoutForm $checkoutForm
* @param Order $order
* @param OrderProduct $orderProduct
* @param CustomerMailer $customerMailer
* @param OrderToken $orderToken
* @param OrderRepository $orderRepository
*/
public function __construct(
CheckoutSession $checkoutSession,
CheckoutForm $checkoutForm,
CustomerService $customerService,
CustomerMailer $customerMailer,
Order $order,
OrderProduct $orderProduct,
OrderToken $orderToken,
OrderRepository $orderRepository
)
{
$this->checkoutSession = $checkoutSession;
$this->checkoutForm = $checkoutForm;
$this->customerService = $customerService;
$this->order = $order;
$this->orderProduct = $orderProduct;
$this->customerMailer = $customerMailer;
$this->orderToken = $orderToken;
$this->orderRepository = $orderRepository;
// dd($order);
}
/**
* Store order in database
*
* @param $input
* @return string
*/
public function store($input)
{
// Prepare data
$data = $this->prepareData($input);
// Fill data and save order
if (!$this->order
->fill($data)
->save()
) {
// Todo message
return \Redirect::back();
};
// Delivery time from order depends on the latest deliverable product
// Start with a default 'in_stock' value
$orderDeliveryTime = 'inStock';
$orderDeliveryTimeCount = 0;
$products = [];
// Add products to database
foreach ($this->checkoutSession->cart()->products() as $product) {
// Create title
$title_parts = [];
if (strtolower($product['data']->brand_name) != 'toebehoren') $title_parts[] = $product['data']->brand_name;
$title_parts[] = $product['data']->name;
$title_parts[] = (\Lang::has('pages/products.' . $product['data']->product_group) ? \Lang::get('pages/products.' . $product['data']->product_group) : $product['data']->product_group);
$title_parts[] = $product['data']->filter_class;
// $title_parts[] = implode(' ', [$product['data']->special_1, $product['data']->special_2]);
$title_parts[] = implode(' ', [$product['data']->special_1]);
$title = implode(' ', $title_parts);
// Update orderDeliveryTime if product is not in stock
if( ! empty($product['data']->delivery_time) &&
$product['data']->delivery_time != 'inStock' &&
$product['data']->delivery_time != 'onRequest')
{
// Format is "del_time{count}"
$count = str_replace('del_time','',$product['data']->delivery_time);
// Convert to an integer
$count = (int) $count;
// Check of product delivery time is longer
if($count > $orderDeliveryTimeCount)
{
// Set new delivery time
$orderDeliveryTime = 'del_time' . $count;
$orderDeliveryTimeCount++;
}
}
// Create description
$description = $product['data']->composition_formatted;
$product = $products[] = [
'order_id' => $this->order->id,
'internal_article_number' => $product['data']->internal_article_number,
'pick_number' => $product['data']->pick_number,
'title' => $title,
'description' => $description,
'delivery_time' => $product['data']->delivery_time,
'composition' => json_encode($product['data']->composition),
'quantity' => $product['quantity'],
'original_price' => $product['data']->price * $product['quantity'],
'original_price_ex' => $product['data']->getPriceExVat(),
'price' => $product['data']->getDiscountPrice(
$product['quantity'],
$this->checkoutSession->cart()->getCouponCode(),
$this->checkoutSession->cart()->getBatchId()
),
'price_ex' => $product['data']->getDiscountPriceExVat(
$product['quantity'],
$this->checkoutSession->cart()->getCouponCode(),
$this->checkoutSession->cart()->getBatchId()
),
'discount_description' => $product['data']->getDiscountSummary(
$product['quantity'],
$this->checkoutSession->cart()->getCouponCode(),
$this->checkoutSession->cart()->getBatchId()
),
'discount_number_of_items_for_free' => $product['data']->getNumberOfFreeProducts(
$product['quantity'],
$this->checkoutSession->cart()->getCouponCode(),
$this->checkoutSession->cart()->getBatchId()
),
'tax_name' => $product['data']->tax_name,
'tax_rate' => $product['data']->tax_rate
];
// Fill & save product
if (!$this->orderProduct->create($product)) {
// Todo message
return \Redirect::back();
}
}
// Set orderId in the session
$data['orderId'] = $this->order->id;
$this->checkoutSession->payment()->set($data);
// Generate token and update database
$token = $this->orderToken->generate(array_merge($data, ['created_at' => $this->order->created_at]));
$this->order->order_token = $token;
// Set delivery
$this->order->delivery_time = $orderDeliveryTime;
$this->order->save();
//Set the order_id in the checkoutSession
$this->checkoutSession->setOrderId($this->order->id);
// Send confirmation e-mail
// Can't insert Order object to mail template :-S have to use arrays. (Laravel limitation)
$data['invoice_full_name'] = $this->order->getFullInvoiceName();
$data['invoice_full_last_name'] = $this->order->getFullInvoiceLastName();
$data['invoice_full_address'] = $this->order->getFullInvoiceAddress();
$data['shipping_full_address'] = $this->order->getFullShippingAddress();
$data['dpd_full_information'] = $this->order->getFullDpdAddress();
//todo: uit gezet om dat er geen use van vond (Tim)
// $data['vat_reverse_charge'] = $this->vatIsNotDutch($this->order-invoice_company>_vat);
$data['sub_total'] = $this->order->getSubTotal();
$data['sub_total_ex_vat'] = $this->order->getSubTotalExVat();
$data['discount_price'] = $this->order->discount_price;
$data['discount_price_ex_vat'] = $this->order->getDiscountPriceExVat();
$data['discount_percentage'] = $this->order->discount_percentage;
$data['shipping_costs'] = $this->order->shipping_costs;
$data['shipping_costs_ex_vat'] = $this->order->getShippingCostsExVat();
$data['products'] = $products;
$data['taxes'] = $this->order->getTaxTotals();
$data['total_ex_vat'] = $this->order->getPriceTotalExVat();
$data['order_delivery_time'] = $orderDeliveryTime;
$data['order'] = $this->order;
//$data['invoice'] = $this->generateInvoicePdf($this->order->id);
// Hard to refactor because of: Serialization of 'Closure' is not allowed error...
/*\Mail::queue('emails.order.received', $data, function($message) use ($data)
{
$pdf = \PDF::loadView('pdfs.invoice', ['order' => $data['order']]);
$message->to($data['invoice_email'])->subject( \Lang::get('emails/order/received.subject'));
if($pdf) $message->attachData($pdf->output(), \Lang::get('pdfs/invoice.fileName',[ 'orderNumber' => $data['order_number'] ]) . '.pdf');
});*/
$this->customerMailer->sendOrderReceived($data);
//Send email to shop owner
$this->customerMailer->sendOrderReceivedToShop($data);
}
/**
* This function will redirect to the payment
*
* @return Redirect to chosen payment
*/
public function redirectToPayment()
{
$paymentForm = \Shop::getPageService()->page('paymentForm')->route;
return \Redirect::to($paymentForm);
}
/**
* @param $orderId
* @return mixed
*/
public function generateInvoicePdf($orderId)
{
$order = $this->order->findOrFail($orderId);
return \PDF::loadView('pdfs.invoice', ['order' => $order]);
}
/**
* @param $orderId
* @return mixed
*/
public function streamInvoicePdf($orderId)
{
$order = $this->order->findOrFail($orderId);
$pdf = \PDF::loadView('pdfs.invoice', ['order' => $order]);
return $pdf->stream(\Lang::get('pdfs/invoice.fileName', ['orderNumber' => $order->invoice_id]) . '.pdf');
}
/**
* @param $orderId
* @return mixed
*/
public function downloadInvoicePdf($orderId)
{
$order = $this->order->findOrFail($orderId);
//Set the locale to the language of the order
\App::setLocale($order->language->iso_2);
$pdf = \PDF::loadView('pdfs.invoice', ['order' => $order]);
return $pdf->download(\Lang::get('pdfs/invoice.fileName', ['orderNumber' => $order->invoice_id]) . '.pdf');
}
/*
* Returns an order by token
*
* @return KommaApp/Shop/Orders/Order
*/
public function getOrderByToken($token)
{
return $this->orderRepository->getOrderFromToken($token);
}
/**
* Check what to do with the shipping address
*
* @param $input
* @return array
*/
public function updateShippingAddress($input)
{
if (!isset($input['shipping-type'])) $input['shipping-type'] = 'invoice';
switch ($input['shipping-type']) {
case 'add-shipping-address':
$this->checkoutSession->shipping()->save();
return $input;
break;
case 'dpd-parcel-shop':
\Session::put('checkout.shipping.dpd_carrier_shop_id', $input['dpd_carrier_shop_id']);
\Session::put('checkout.shipping.dpd_carrier_shop_details', $input['dpd_carrier_shop_details']);
default:
$input = array_merge($input, $this->checkoutSession->shipping()->useInvoiceAddress());
return $input;
break;
}
}
/**
* @param $input
* @return array
*/
protected function prepareData($input)
{
// Prepare keys
$data = [];
foreach ($input as $key => $value) {
$newKey = str_replace('-', '_', $key);
$data[$newKey] = $value;
}
// Set the shipping country in the cart for the calculation of the shipping costs
$this->checkoutSession->cart()->setShippingCountryIdByIso2($data['shipping_country']);
// Check if there is a customer to use for the order. Or create a new one.
if (!$customer = \Auth::customer()->get()) {
$existingCustomer = $this->customerService->getCustomerIfExists([
'email' => $input['invoice-email'],
// 'postal' => $input['invoice-postal'],
]);
if(!$existingCustomer) {
// dd('creating new customer. email and postal combination not found in existing user: '.$input['invoice-email'].' '.$input['invoice-postal']);
$customer = $this->createCustomer();
} else {
// dd('linking order to exisiting user');
$existingCustomer->title = $input['invoice-title'];
$existingCustomer->first_name = $input['invoice-first-name'];
if(isset($input['invoice-name-insertion'])) {
$existingCustomer->name_insertion = $input['invoice-name-insertion'];
}
$existingCustomer->last_name = $input['invoice-title'];
$existingCustomer->telephone = $input['invoice-telephone'];
$existingCustomer->company = $input['invoice-company'];
$existingCustomer->street = $input['invoice-street'];
$existingCustomer->house_number = $input['invoice-house-number'];
$existingCustomer->house_number_suffix = $input['invoice-house-number-suffix'];
$existingCustomer->postal = $input['invoice-postal'];
$existingCustomer->city = $input['invoice-city'];
$existingCustomer->country = $input['invoice-country'];
// $existingCustomer->active = 1; //1 for can login. 0 for cannot login. e.g. ordered as guest who does not know he has an account. //Leave this variable for what it is.
$existingCustomer->save();
$customer = $existingCustomer;
}
}
$customerId = $customer->id;
// Get Shop id
$shopId = \Shop::getId();
$orderNumber = Order::getNewOrderNumber();
$data['shop_id'] = $shopId;
$data['customer_id'] = $customerId;
$data['order_number'] = $orderNumber;
$data['language_id'] = \Shop::getLanguageService()->getLanguageIdFromUri();
$data['domain_country'] = \Shop::getDomainCountry();
$data['coupon_code'] = $this->checkoutSession->cart()->getCouponCode();
$data['invoice_id'] = Order::getNewInvoiceId();
// Get genders from title
$data['invoice_gender'] = $this->order->getInvoiceGender($input);
$data['shipping_gender'] = $this->order->getShippingGender($input);
//Get the shop Country from the tops config
$shop_country = \Config::get('komma/tops.shop_country');
if (!isset($data['dpd_carrier_shop_id']) || empty($data['dpd_carrier_shop_id'])) $data['dpd_carrier_shop_id'] = null;
//Lets fill the price and VAT price based on the EU rules
if (!empty($input['invoice-company'])) {
//This will check the vat number and if correct will return the Vat Country (iso2)
$vat_country = $this->checkVatNumber($input['invoice-company-vat']);
} else {
$data['invoice_company_vat'] = '';
}
//If there is an vat_country and the vat_country is not the same as the shop AND the shipping_country is not the same as the shop_country
if (!empty($vat_country) && $vat_country != $shop_country && $shop_country != $data['shipping_country']) {
//EU cross-border shopping. no VAT
//This rule can only be aplied to an EU company When it is schipped to an other EU country that is NOT the country of the shop
$data['shipping_costs'] = $this->checkoutSession->cart()->shipping(); //TODO: This is the fix for the bug on the next line
// $data['shipping_costs'] = $this->checkoutSession->cart()->shippingWithoutVat(); //TODO: This was a bug. Since the data is saved in the order. And further after the prepareData call a similar call on the order itself is done causing shipping by applied twice.
$data['original_price'] = $this->checkoutSession->cart()->subTotalOriginalProductPriceWithoutVat();
$data['price_total'] = $this->checkoutSession->cart()->totalPriceExVat();
$data['discount_price'] = $this->checkoutSession->cart()->getDiscountExVat();
$data['discount_price'] = $this->checkoutSession->cart()->getDiscountExVat();
$data['discount_percentage'] = $this->checkoutSession->cart()->getDiscountPercentage();
$data['discount'] = $this->checkoutSession->cart()->getDiscountExVat();
$data['discount_description'] = '(-' . $this->checkoutSession->cart()->getDiscountPercentage() . '%) -€ ' . price($this->checkoutSession->cart()->getDiscountExVat());
} //The vat_country doesn't exist (private buyer) Or the buying company is based in the same nation as the shop
else {
$data['shipping_costs'] = $this->checkoutSession->cart()->shipping();
$data['original_price'] = $this->checkoutSession->cart()->subTotalOriginalProductPrice();
$data['price_total'] = $this->checkoutSession->cart()->totalPrice();
$data['discount_price'] = $this->checkoutSession->cart()->getDiscount();
$data['discount_percentage'] = $this->checkoutSession->cart()->getDiscountPercentage();
$data['discount'] = $this->checkoutSession->cart()->getDiscount();
$data['discount_description'] = '(-' . $this->checkoutSession->cart()->getDiscountPercentage() . '%) -€ ' . price($this->checkoutSession->cart()->getDiscount());
}
$data['product_total_ex'] = $this->checkoutSession->cart()->totalProductPriceExVat();
//remarks, convert \n to <br/>
$data['remarks'] = nl2br($data['remarks']);
$data['status'] = Order::OPEN;
$data['ordered_at'] = Carbon::now();
return $data;
}
/**
* This function will check the country of the vat number
* And will check the VAT-regex for the given country.
*
* @param $vatNumber
* @return mixed
*/
public function checkVatNumber($vatNumber)
{
//Check if the vatNumber is not empty
if (empty($vatNumber)) {
//No VAT -> return false
return false;
}
//The big EU vat checker
if (!$matched_vat = preg_match("((AT)?U[0-9]{8}|(BE)?0[0-9]{9}|(BG)?[0-9]{9,10}|(CY)?[0-9]{8}L|(CZ)?[0-9]{8,10}|(DE)?[0-9]{9}|(DK)?[0-9]{8}|(EE)?[0-9]{9}|(EL|GR)?[0-9]{9}|(ES)?[0-9A-Z][0-9]{7}[0-9A-Z]|(FI)?[0-9]{8}|(FR)?[0-9A-Z]{2}[0-9]{9}|(GB)?([0-9]{9}([0-9]{3})?|[A-Z]{2}[0-9]{3})|(HU)?[0-9]{8}|(IE)?[0-9]S[0-9]{5}L|(IT)?[0-9]{11}|(LT)?([0-9]{9}|[0-9]{12})|(LU)?[0-9]{8}|(LV)?[0-9]{11}|(MT)?[0-9]{8}|(NL)?[0-9]{9}B[0-9]{2}|(PL)?[0-9]{10}|(PT)?[0-9]{9}|(RO)?[0-9]{2,10}|(SE)?[0-9]{12}|(SI)?[0-9]{8}|(SK)?[0-9]{10})", $vatNumber)) {
//Regex is not correct so return false
return false;
}
//The vat is correct and an VAT of the EU
//extract the country code from the vatNumber
$countryCode = substr($vatNumber, 0, 2);
$vatNumber = substr($vatNumber, 2);
//Check the VAT with the ec.europe load the soap client
$client = new \SoapClient("http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl");
if ($client) {
$params = [
'countryCode' => $countryCode,
'vatNumber' => $vatNumber
];
try {
try {
$response = $client->checkVat($params);
} catch (\SoapFault $e) {
//Respons can not be checked, but we will accept the VAT
return $countryCode;
}
if ($response->valid) {
//If all is well return countryCode
return $countryCode;
} else {
return false;
}
} catch (SoapFault $e) {
//Respons can not be checked, but we will accept the VAT
return $countryCode;
}
}
return false;
}
public function createCustomer()
{
//No customer, create a customer
$input = [];
foreach ($this->checkoutSession->customer()->get() as $key => $data) {
$input[str_replace('invoice-', '', $key)] = $data;
}
$input['first_name'] = $input['first-name'];
if (isset($input['name_insertion'])) {
$input['name_insertion'] = $input['name-insertion'];
}
$input['last_name'] = $input['last-name'];
$input['house_number'] = $input['house-number'];
$input['house_number_suffix'] = $input['house-number-suffix'];
//Only save the VAT when the comany is not empty
$input['company_vat'] = (!empty(trim($input['company'])) ? $input['company-vat'] : "");
$input['password'] = md5(time());
$input['customer_email'] = $input['email'];
return $this->customerService->streamLinedStoreNewCustomer($input);
}
/**
* Changes the order status. And optionally removes the order from a shipment if you pass a shipment id.
* Returns an array containing a message and code key to return
*
* @param $order
* @param $status
* @param $shipmentId
* @return array
*/
public function changeOrderStatus($order, $status, $shipmentId = null) {
$statusses = [Order::BACKORDER, Order::CANCELLED, Order::COMPLETE, Order::OPEN, Order::PARTLYSHIPPED, Order::PAYED, Order::SENT, Order::TREATMENT];
if(!in_array($status, $statusses, true)) return ['code' => 500, 'message' => 'Invalid order status'];
$order = Order::find($order);
if(!$order) return ['code' => 404, 'message' => 'Order not found'];
$order->status = $status;
$order->save();
if($order->status == Order::BACKORDER && $shipmentId) {
//remove order from a shipment
/** @var ShipmentService $shipmentService */
$shipmentService = \App::make('Komma\Kms\Shipments\ShipmentService');
$result = $shipmentService->removeOderFromShipment($shipmentId, $order->id);
if($result)
return ['code' => 200, 'message' => 'Changed status successfully and removed order from shipments'];
else
return ['code' => 500, 'message' => 'Changed status successfully but could not remove the order from the shipment'];
}
return ['code' => 200, 'message' => 'Changed status successfully'];
}
}