<?php
declare
(strict_types=1);
namespace
Dan\HelloCash\Console\Command;
use
Dan\HelloCash\Api\Data\SyncLogInterfaceFactory;
use
Dan\HelloCash\Api\HelloCash
as
HelloCashApi;
use
Dan\HelloCash\Enum\SyncLogType;
use
Dan\HelloCash\Exception\SyncException;
use
Dan\HelloCash\Exception\SyncOrderException;
use
Dan\HelloCash\Model\SyncLogRepository;
use
Magento\Catalog\Api\ProductRepositoryInterface;
use
Magento\Catalog\Model\ProductFactory;
use
Magento\Config\Model\Config;
use
Magento\Customer\Api\CustomerRepositoryInterface;
use
Magento\Framework\App\State;
use
Magento\Framework\DB\Transaction;
use
Magento\Framework\ObjectManagerInterface;
use
Magento\Framework\View\Result\PageFactory;
use
Magento\Quote\Model\Quote\Address\Rate
as
ShippingRate;
use
Magento\Quote\Model\QuoteManagement;
use
Magento\Sales\Api\OrderRepositoryInterface;
use
Magento\Sales\Model\Order\Email\Sender\OrderSender;
use
Magento\Store\Api\Data\StoreInterface;
use
Magento\Customer\Model\Customer\Interceptor
as
CustomerInterceptor;
use
Magento\Customer\Model\CustomerFactory;
use
Magento\Framework\App\Area;
use
Magento\Framework\Encryption\Encryptor;
use
Magento\Quote\Model\QuoteFactory;
use
Magento\Store\Model\StoreManagerInterface;
use
Symfony\Component\Console\Input\InputArgument;
use
Symfony\Component\Console\Input\InputInterface;
use
Symfony\Component\Console\Input\InputOption;
use
Symfony\Component\Console\Output\OutputInterface;
use
Magento\Sales\Model\Service\InvoiceService;
use
Magento\Sales\Model\Order\Email\Sender\InvoiceSender;
class
SyncOrders
extends
SyncCommand
{
const
NAME_ARGUMENT =
'name'
;
const
NAME_OPTION =
'option'
;
protected
CustomerFactory
$customerFactory
;
protected
CustomerInterceptor
$customer
;
protected
OutputInterface
$output
;
protected
StoreInterface
$store
;
protected
StoreManagerInterface
$storeManager
;
protected
QuoteFactory
$quoteFactory
;
protected
PageFactory
$resultPageFactory
;
protected
OrderRepositoryInterface
$orderRepository
;
protected
ProductRepositoryInterface
$productRepository
;
protected
$customerRepository
;
protected
QuoteFactory
$quote
;
protected
QuoteManagement
$quoteManagement
;
protected
OrderSender
$orderSender
;
protected
ProductFactory
$productFactory
;
protected
ObjectManagerInterface
$objectManager
;
protected
ShippingRate
$shippingRate
;
protected
InvoiceService
$invoiceService
;
protected
Transaction
$transaction
;
protected
InvoiceSender
$invoiceSender
;
private
string
$customerEmail
;
private
string
$customerPassword
;
private
string
$customerPhone
;
protected
function
__construct(
HelloCashApi
$api
,
Config
$config
,
Encryptor
$encryptor
,
SyncLogRepository
$syncLogRepository
,
SyncLogInterfaceFactory
$syncLogFactory
,
CustomerFactory
$customerFactory
,
StoreManagerInterface
$storeManager
,
CustomerRepositoryInterface
$customerRepository
,
QuoteFactory
$quote
,
ProductFactory
$productFactory
,
ObjectManagerInterface
$objectManager
,
ShippingRate
$shippingRate
,
State
$state
,
Transaction
$transaction
)
{
$this
->customerFactory =
$customerFactory
;
$this
->storeManager =
$storeManager
;
$this
->customerRepository =
$customerRepository
;
$this
->quote =
$quote
;
$this
->productFactory =
$productFactory
;
$this
->state =
$state
;
$this
->objectManager =
$objectManager
;
$this
->shippingRate =
$shippingRate
;
$this
->transaction =
$transaction
;
parent::__construct(
$api
,
$config
,
$encryptor
,
$syncLogRepository
,
$syncLogFactory
);
$this
->customerEmail = (string)
$this
->config->getConfigDataValue(
'hello_cash_general/sync_order/customer_email'
);
$this
->customerPassword =
$this
->encryptor->decrypt(
$this
->config->getConfigDataValue(
'hello_cash_general/sync_order/customer_password'
));
$this
->customerPhone = (string)
$this
->config->getConfigDataValue(
'hello_cash_general/sync_order/customer_phone'
);
}
protected
function
configure()
{
$this
->setName(
'dan_hellocash:sync-orders'
);
$this
->setDescription(
'Imports the HelloCash orders into your Magento shop.'
);
$this
->setDefinition([
new
InputArgument(self::NAME_ARGUMENT, InputArgument::OPTIONAL,
'Name'
),
new
InputOption(self::NAME_OPTION,
'-a'
, InputOption::VALUE_NONE,
'Option functionality'
)
]);
parent::configure();
}
protected
function
execute(
InputInterface
$input
,
OutputInterface
$output
)
{
try
{
$this
->output =
$output
;
$this
->state->setAreaCode(Area::AREA_FRONTEND);
$this
->store =
$this
->storeManager->getStore();
$this
->websiteId =
$this
->storeManager->getWebsite()->getId();
$this
->createSyncLog(SyncLogType::ORDERS);
$ordersHellocash
=
$this
->getOrders();
$this
->syncLog->setTotal((int)
$ordersHellocash
->
count
);
$this
->syncLogRepository->save(
$this
->syncLog);
foreach
(
$ordersHellocash
->invoices
as
$orderHellocash
) {
try
{
if
(
'1'
===
$orderHellocash
->invoice_cancellation) {
continue
;
}
$orderHellocash
=
$this
->getOrder((int)
$orderHellocash
->invoice_id);
$this
->createOrder(
$orderHellocash
);
}
catch
(SyncOrderException
$exception
) {
$this
->handleOrderError(
$orderHellocash
,
$exception
);
} finally {
$this
->syncLog->setProcessed(
$this
->syncLog->getProcessed() + 1);
$this
->syncLogRepository->save(
$this
->syncLog);
}
}
$this
->handleSuccess();
}
catch
(SyncException
$exception
) {
$this
->handleFatalError(
'A problem occurred calling the HelloCash API. (status: '
.
$exception
->getStatusCode() .
', message: "'
.
$exception
->getMessage() .
'")'
);
} finally {
$this
->finishSync();
}
}
protected
function
createOrder(\stdClass
$orderHelloCash
)
{
$this
->createCustomer(
$orderHelloCash
);
$quote
=
$this
->quote->create();
$quote
->setStore(
$this
->store);
$quote
->setCurrency();
$customer
=
$this
->customerRepository->getById(
$this
->customer->getId());
$quote
->assignCustomer(
$customer
);
foreach
(
$orderHelloCash
->items
as
$item
) {
$product
=
$this
->productFactory
->create()
->loadByAttribute(
'hellocash_article_id'
, (int)
$item
->item_article_id);
if
(!
$product
) {
throw
new
SyncOrderException(
'Product not found. (HelloCash ID: '
.
$item
->item_article_id .
', name: "'
.
$item
->item_name .
'")'
);
}
$product
->setPrice((float)
$item
->item_price);
$quote
->addProduct(
$product
,
(float)
$item
->item_quantity
);
}
$addressData
=
$this
->createAddressData(
$orderHelloCash
->company);
$quote
->getBillingAddress()->addData(
$addressData
);
$quote
->getShippingAddress()->addData(
$addressData
);
$this
->shippingRate
->setCode(
'hellocash_hellocash'
)
->getPrice();
$shippingAddress
=
$quote
->getShippingAddress()
->addShippingRate(
$this
->shippingRate);
$shippingAddress
->setCollectShippingRates(true);
$shippingAddress
->collectShippingRates();
$shippingAddress
->setShippingMethod(
'hellocash_hellocash'
);
$quote
->setPaymentMethod(
'hellocash'
);
$quote
->setInventoryProcessed(true);
$quote
->save();
$quote
->getPayment()->importData([
'method'
=>
'hellocash'
]);
$quote
->collectTotals()->save();
$quoteManagement
=
$this
->objectManager->create(QuoteManagement::
class
);
$order
=
$quoteManagement
->submit(
$quote
);
$order
->setHellocashInvoiceId((int)
$orderHelloCash
->invoice_id)
->setEmailSent(1)
->setStatus(
'pending'
)
->save();
if
(!
$order
->getEntityId()) {
throw
new
SyncOrderException(
'Failed to get the order ID after saving.'
);
}
$this
->createInvoice(
$order
);
$order
->setStatus(
'complete'
)
->save();
return
$order
;
}
protected
function
createCustomer(\stdClass
$invoiceHellocash
): CustomerInterceptor
{
if
(isset(
$this
->customer)) {
return
$this
->customer;
}
$this
->verifyCustomerCredentials();
$this
->customer =
$this
->customerFactory
->create()
->setWebsiteId(
$this
->websiteId)
->setStore(
$this
->store);
if
(!
$this
->customer->loadByEmail(
$this
->customerEmail)->getId()) {
$this
->customer
->setFirstname(
'Cashier'
)
->setLastname(
'HelloCash'
)
->setEmail(
$this
->customerEmail)
->setPassword(
$this
->customerPassword);
$this
->customer->save();
}
return
$this
->customer;
}
protected
function
createAddressData(\stdClass
$companyHellocash
):
array
{
$address
= [
'firstname'
=>
$companyHellocash
->name,
'lastname'
=>
'HelloCash'
,
'country_id'
=>
'AT'
,
'city'
=>
$companyHellocash
->city,
'street'
=>
$companyHellocash
->street,
'postcode'
=>
$companyHellocash
->postalCode,
'telephone'
=>
$this
->customerPhone,
'save_in_address_book'
=> 1
];
return
$address
;
}
public
function
createInvoice(
$order
)
{
$this
->invoiceService =
$this
->objectManager->create(InvoiceService::
class
);
$invoice
=
$this
->invoiceService
->prepareInvoice(
$order
)
->register()
->save();
$this
->transaction
->addObject(
$invoice
)
->addObject(
$invoice
->getOrder())
->save();
$this
->invoiceSender =
$this
->objectManager->create(InvoiceSender::
class
);
$this
->invoiceSender->send(
$invoice
);
$order
->addCommentToStatusHistory(__(
'Notified customer about invoice creation #%1.'
,
$invoice
->getId()))
->setIsCustomerNotified(true)
->save();
return
$invoice
;
}
protected
function
verifyCustomerCredentials()
{
if
(
empty
(
$this
->customerEmail)) {
throw
new
SyncException(
'The customer email is not set in the module\'s admin configuration! Please set it.'
);
}
if
(
empty
(
$this
->customerPassword)) {
throw
new
SyncException(
'The customer password is not set in the module\'s admin configuration! Please set it.'
);
}
if
(
empty
(
$this
->customerPhone)) {
throw
new
SyncException(
'The customer phone number is not set in the module\'s admin configuration! Please set it.'
);
}
}
}