Initial xentral_oss_20.3.c9ffacf
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF;
|
||||
|
||||
use Xentral\Components\SchemaCreator\Collection\SchemaCollection;
|
||||
use Xentral\Components\SchemaCreator\Index;
|
||||
use Xentral\Components\SchemaCreator\Option\TableOption;
|
||||
use Xentral\Components\SchemaCreator\Schema\TableSchema;
|
||||
use Xentral\Components\SchemaCreator\Type;
|
||||
use Xentral\Core\DependencyInjection\ContainerInterface;
|
||||
|
||||
final class Bootstrap
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public static function registerServices(): array
|
||||
{
|
||||
return [
|
||||
'PurchaseOrderInformationRepository' => 'onInitPurchaseOrderInformationRepository',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*
|
||||
* @return PurchaseOrderInformationRepository
|
||||
*/
|
||||
public static function onInitPurchaseOrderInformationRepository(ContainerInterface $container
|
||||
): PurchaseOrderInformationRepository {
|
||||
return new PurchaseOrderInformationRepository(
|
||||
$container->get('Database')
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
use DateTime;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\MissingInformationException;
|
||||
|
||||
class AcknowledgementItem
|
||||
{
|
||||
/**
|
||||
* Shipping 100 percent of ordered product
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CODE_ACCEPTED = '00';
|
||||
/**
|
||||
* Canceled out of stock
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CODE_REJECT_OUT_OF_STOCK = '03';
|
||||
/**
|
||||
* No article found for SKU
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CODE_REJECT_INVALID_SKU = '02';
|
||||
|
||||
const AVAILABLE_CODES = [
|
||||
'00' => 'Shipping 100 percent of ordered product',
|
||||
'02' => 'Canceled due to missing/invalid SKU',
|
||||
'03' => 'Canceled out of stock',
|
||||
'04' => 'Canceled due to duplicate Amazon Ship ID',
|
||||
'05' => 'Canceled due to missing/invalid Bill To Location Code',
|
||||
'06' => 'Canceled due to missing/invalid Ship From Location Code',
|
||||
'07' => 'Canceled due to missing/invalid Customer Ship to Name',
|
||||
'08' => 'Canceled due to missing/invalid Customer Ship to Address Line 1',
|
||||
'10' => 'Canceled due to missing/invalid Customer Ship to City',
|
||||
'11' => 'Canceled due to missing/invalid Customer Ship to State',
|
||||
'12' => 'Canceled due to missing/invalid Customer Ship to Postal Code',
|
||||
'13' => 'Canceled due to missing/invalid Customer Ship to Country Code',
|
||||
'20' => 'Canceled due to missing/invalid Shipping Carrier/Shipping Method',
|
||||
'21' => 'Canceled due to missing/invalid Ship to Address Line 2',
|
||||
'22' => 'Canceled due to missing/invalid Ship to Address Line 3',
|
||||
'50' => 'Canceled due to Tax Nexus Issue',
|
||||
'51' => 'Canceled due to Restricted SKU/Qty',
|
||||
];
|
||||
|
||||
/** @var PurchaseOrderItem */
|
||||
private $item;
|
||||
|
||||
/** @var string */
|
||||
private $code;
|
||||
|
||||
public function __construct(PurchaseOrderItem $item, string $code)
|
||||
{
|
||||
$this->item = $item;
|
||||
$this->code = $code;
|
||||
}
|
||||
|
||||
public function isRejected(): bool
|
||||
{
|
||||
return $this->code !== self::CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
public function isAccepted(): bool
|
||||
{
|
||||
return $this->code === self::CODE_ACCEPTED;
|
||||
}
|
||||
|
||||
public function getStatusCode(): string
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
$data = [
|
||||
'itemSequenceNumber' => $this->item->getItemSequenceNumber(),
|
||||
'buyerProductIdentifier' => $this->item->getBuyerProductIdentifier(),
|
||||
'vendorProductIdentifier' => $this->item->getVendorProductIdentifier(),
|
||||
'acknowledgedQuantity' => $this->item->getQuantity()->toArray(),
|
||||
];
|
||||
|
||||
unset($data['acknowledgedQuantity']['unitSize']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class Address
|
||||
{
|
||||
/** @var string */
|
||||
private $name;
|
||||
/** @var array */
|
||||
private $addressLines;
|
||||
/** @var string */
|
||||
private $city;
|
||||
/** @var string */
|
||||
private $countryCode;
|
||||
/** @var string */
|
||||
private $postalCode;
|
||||
/** @var string */
|
||||
private $stateOrRegion;
|
||||
/** @var string */
|
||||
private $phone;
|
||||
|
||||
public function setName(string $name): self
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setAddressLines(array $addressLines): self
|
||||
{
|
||||
$this->addressLines = $addressLines;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCity(string $city): self
|
||||
{
|
||||
$this->city = $city;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setCountryCode(string $countryCode): self
|
||||
{
|
||||
$this->countryCode = $countryCode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
public function setPostalCode(string $postalCode): self
|
||||
{
|
||||
$this->postalCode = $postalCode;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setStateOrRegion(string $stateOrRegion): self
|
||||
{
|
||||
$this->stateOrRegion = $stateOrRegion;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setPhone(string $phone): self
|
||||
{
|
||||
$this->phone = $phone;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getName(): string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
public function getAddressLines(): array
|
||||
{
|
||||
return $this->addressLines;
|
||||
}
|
||||
|
||||
public function getCity(): string
|
||||
{
|
||||
return $this->city;
|
||||
}
|
||||
|
||||
public function getCountryCode(): string
|
||||
{
|
||||
return $this->countryCode;
|
||||
}
|
||||
|
||||
public function getPostalCode(): string
|
||||
{
|
||||
return $this->postalCode;
|
||||
}
|
||||
|
||||
public function getStateOrRegion(): string
|
||||
{
|
||||
return $this->stateOrRegion;
|
||||
}
|
||||
|
||||
public function getPhone(): string
|
||||
{
|
||||
return $this->phone;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_filter([
|
||||
'name' => $this->name,
|
||||
'addressLine1' => $this->addressLines[0],
|
||||
'addressLine2' => $this->addressLines[1],
|
||||
'addressLine3' => $this->addressLines[2],
|
||||
'city' => $this->city,
|
||||
'stateOrRegion' => $this->stateOrRegion,
|
||||
'postalCode' => $this->postalCode,
|
||||
'countryCode' => $this->countryCode,
|
||||
'phone' => $this->phone,
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class Container
|
||||
{
|
||||
/** @var string */
|
||||
private $containerType;
|
||||
/** @var string */
|
||||
private $containerIdentifier;
|
||||
/** @var string */
|
||||
private $length;
|
||||
/** @var string */
|
||||
private $width;
|
||||
/** @var string */
|
||||
private $height;
|
||||
/** @var string */
|
||||
private $unitOfMeasure;
|
||||
/** @var array */
|
||||
private $items = [];
|
||||
|
||||
public function __construct(string $containerIdentifier, string $containerType = 'carton')
|
||||
{
|
||||
$this->containerIdentifier = $containerIdentifier;
|
||||
$this->containerType = $containerType;
|
||||
}
|
||||
|
||||
public function setDimensions(string $length, string $width, string $height, string $unitOfMeasure = 'CM')
|
||||
{
|
||||
$this->length = $length;
|
||||
$this->width = $width;
|
||||
$this->height = $height;
|
||||
$this->unitOfMeasure = $unitOfMeasure;
|
||||
}
|
||||
|
||||
public function addItem(
|
||||
string $itemSequenceNumber,
|
||||
string $buyerProductIdentifier,
|
||||
string $vendorProductIdentifier,
|
||||
Quantity $packedQuantity
|
||||
) {
|
||||
$quantity = $packedQuantity->toArray();
|
||||
unset($quantity['unitSize']);
|
||||
$this->items[] = [
|
||||
'itemSequenceNumber' => (int)$itemSequenceNumber,
|
||||
'buyerProductIdentifier' => $buyerProductIdentifier,
|
||||
'vendorProductIdentifier' => $vendorProductIdentifier,
|
||||
'packedQuantity' => $quantity,
|
||||
];
|
||||
}
|
||||
|
||||
public function getItems(): array
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'containerType' => $this->containerType,
|
||||
'containerIdentifier' => $this->containerIdentifier,
|
||||
'dimensions' => [
|
||||
'length' => $this->length,
|
||||
'width' => $this->width,
|
||||
'height' => $this->height,
|
||||
'unitOfMeasure' => $this->unitOfMeasure,
|
||||
],
|
||||
'weight' => [
|
||||
'unitOfMeasure' => 'KG',
|
||||
'value' => '1',
|
||||
],
|
||||
'packedItems' => $this->items,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class InventoryItem
|
||||
{
|
||||
/** @var Quantity */
|
||||
private $quantity;
|
||||
/** @var string|null */
|
||||
private $vendorProductIdentifier;
|
||||
/** @var bool|null */
|
||||
private $isObsolete;
|
||||
/** @var string */
|
||||
private $buyerProductIdentifier;
|
||||
|
||||
public function __construct(
|
||||
Quantity $quantity,
|
||||
?string $vendorProductIdentifier = null,
|
||||
?bool $isObsolete = false,
|
||||
?string $buyerProductIdentifier = null
|
||||
) {
|
||||
$this->quantity = $quantity;
|
||||
$this->vendorProductIdentifier = $vendorProductIdentifier;
|
||||
$this->isObsolete = $isObsolete;
|
||||
$this->buyerProductIdentifier = $buyerProductIdentifier;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_filter(
|
||||
[
|
||||
'buyerProductIdentifier' => $this->buyerProductIdentifier,
|
||||
'vendorProductIdentifier' => $this->vendorProductIdentifier,
|
||||
'availableQuantity' => $this->quantity->toArray(),
|
||||
'isObsolete' => $this->isObsolete,
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
use DateTime;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\MissingInformationException;
|
||||
|
||||
class Invoice
|
||||
{
|
||||
/** @var string */
|
||||
private $invoiceNumber;
|
||||
/** @var DateTime */
|
||||
private $invoiceDate;
|
||||
/** @var Address */
|
||||
private $billToAddress;
|
||||
/** @var Price */
|
||||
private $invoiceTotal;
|
||||
/** @var array|InvoiceItem[] */
|
||||
private $items;
|
||||
/** @var SellingParty */
|
||||
private $remitToParty;
|
||||
/** @var Warehouse */
|
||||
private $warehouse;
|
||||
|
||||
public function __construct(
|
||||
string $invoiceNumber,
|
||||
DateTime $invoiceDate,
|
||||
SellingParty $remitToParty,
|
||||
Warehouse $warehouse
|
||||
) {
|
||||
$this->invoiceNumber = $invoiceNumber;
|
||||
$this->invoiceDate = $invoiceDate;
|
||||
$this->remitToParty = $remitToParty;
|
||||
$this->warehouse = $warehouse;
|
||||
}
|
||||
|
||||
public function addItem(InvoiceItem $item): self
|
||||
{
|
||||
$this->items[] = $item;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setBillToAddress(Address $address)
|
||||
{
|
||||
$this->billToAddress = $address;
|
||||
}
|
||||
|
||||
public function setInvoiceTotal(Price $invoiceTotal): self
|
||||
{
|
||||
$this->invoiceTotal = $invoiceTotal;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
if (!$this->invoiceTotal) {
|
||||
throw MissingInformationException::property('invoiceTotal');
|
||||
}
|
||||
|
||||
return [
|
||||
'invoiceNumber' => $this->invoiceNumber,
|
||||
'invoiceDate' => $this->invoiceDate,
|
||||
'remitToParty' => $this->remitToParty->toArray(),
|
||||
'shipFromParty' => $this->formatShipFromParty(),
|
||||
'invoiceTotal' => $this->invoiceTotal->toArray(),
|
||||
'taxTotals' => $this->grabTaxTotalsFromInvoiceItems(),
|
||||
'items' => $this->mapInvoiceItemsToArray(),
|
||||
];
|
||||
}
|
||||
|
||||
private function grabTaxTotalsFromInvoiceItems(): array
|
||||
{
|
||||
return array_map(function (InvoiceItem $item){
|
||||
return $item->getTaxDetails()->toArray();
|
||||
}, $this->items);
|
||||
}
|
||||
|
||||
private function mapInvoiceItemsToArray()
|
||||
{
|
||||
return array_map(
|
||||
function (InvoiceItem $item) {
|
||||
return $item->toArray();
|
||||
},
|
||||
$this->items
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently the warehouse uses the taxRegistrationDetails and address of the remitToParty
|
||||
*/
|
||||
private function formatShipFromParty(): array
|
||||
{
|
||||
$data = $this->remitToParty->toArray();
|
||||
$data['partyId'] = $this->warehouse->getWarehouseId();
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class InvoiceItem
|
||||
{
|
||||
/** @var string */
|
||||
private $itemSequenceNumber;
|
||||
/** @var string */
|
||||
private $buyerProductIdentifier;
|
||||
/** @var string */
|
||||
private $vendorProductIdentifier;
|
||||
/** @var Quantity */
|
||||
private $invoicedQuantity;
|
||||
/** @var Price */
|
||||
private $netCost;
|
||||
/** @var string */
|
||||
private $purchaseOrderNumber;
|
||||
/** @var TaxDetails */
|
||||
private $taxDetails;
|
||||
|
||||
public function getItemSequenceNumber(): string
|
||||
{
|
||||
return $this->itemSequenceNumber;
|
||||
}
|
||||
|
||||
public function setItemSequenceNumber(string $itemSequenceNumber): self
|
||||
{
|
||||
$this->itemSequenceNumber = $itemSequenceNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getBuyerProductIdentifier(): string
|
||||
{
|
||||
return $this->buyerProductIdentifier;
|
||||
}
|
||||
|
||||
public function setBuyerProductIdentifier(string $buyerProductIdentifier): self
|
||||
{
|
||||
$this->buyerProductIdentifier = $buyerProductIdentifier;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getVendorProductIdentifier(): string
|
||||
{
|
||||
return $this->vendorProductIdentifier;
|
||||
}
|
||||
|
||||
public function setVendorProductIdentifier(string $vendorProductIdentifier): self
|
||||
{
|
||||
$this->vendorProductIdentifier = $vendorProductIdentifier;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInvoicedQuantity(): Quantity
|
||||
{
|
||||
return $this->invoicedQuantity;
|
||||
}
|
||||
|
||||
public function setInvoicedQuantity(Quantity $invoicedQuantity): self
|
||||
{
|
||||
$this->invoicedQuantity = $invoicedQuantity;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getNetCost(): Price
|
||||
{
|
||||
return $this->netCost;
|
||||
}
|
||||
|
||||
public function setNetCost(Price $netCost): self
|
||||
{
|
||||
$this->netCost = $netCost;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getPurchaseOrderNumber(): string
|
||||
{
|
||||
return $this->purchaseOrderNumber;
|
||||
}
|
||||
|
||||
public function setPurchaseOrderNumber(string $purchaseOrderNumber): self
|
||||
{
|
||||
$this->purchaseOrderNumber = $purchaseOrderNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTaxDetails(): TaxDetails
|
||||
{
|
||||
return $this->taxDetails;
|
||||
}
|
||||
|
||||
public function setTaxDetails(TaxDetails $taxDetails): self
|
||||
{
|
||||
$this->taxDetails = $taxDetails;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'purchaseOrderNumber' => $this->purchaseOrderNumber,
|
||||
'itemSequenceNumber' => $this->itemSequenceNumber,
|
||||
'invoicedQuantity' => $this->invoicedQuantity->toArray(),
|
||||
'netCost' => $this->netCost->toArray(),
|
||||
'taxDetails' => $this->taxDetails->toArray(),
|
||||
// not implemented yet
|
||||
'chargeDetails' => [],
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class Price
|
||||
{
|
||||
/** @var string */
|
||||
private $currency;
|
||||
/** @var float */
|
||||
private $amount;
|
||||
|
||||
public function __construct(string $currency, float $amount)
|
||||
{
|
||||
$this->currency = $currency;
|
||||
$this->amount = $amount;
|
||||
}
|
||||
|
||||
public function getCurrency(): string
|
||||
{
|
||||
return $this->currency;
|
||||
}
|
||||
|
||||
public function getAmount(): float
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'currencyCode' => $this->currency,
|
||||
'amount' => $this->amount,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
use DateTime;
|
||||
use InvalidArgumentException;
|
||||
|
||||
class PurchaseOrder
|
||||
{
|
||||
/** @var string */
|
||||
private $purchaseOrderNumber;
|
||||
/** @var DateTime|false */
|
||||
private $purchaseOrderDate;
|
||||
/** @var array|PurchaseOrderItem[] */
|
||||
private $items;
|
||||
/** @var SellingParty */
|
||||
private $sellingParty;
|
||||
/** @var Address */
|
||||
private $shipToParty;
|
||||
/** @var string */
|
||||
private $warehouseId;
|
||||
/** @var ShipmentDetails */
|
||||
private $shipmentDetails;
|
||||
/** @var array */
|
||||
private $rawData;
|
||||
|
||||
public function __construct(
|
||||
string $purchaseOrderNumber,
|
||||
$purchaseOrderDate,
|
||||
array $items,
|
||||
SellingParty $sellingParty,
|
||||
string $warehouseId,
|
||||
Address $shipToParty,
|
||||
ShipmentDetails $shipmentDetails,
|
||||
array $rawData = []
|
||||
) {
|
||||
$this->purchaseOrderNumber = $purchaseOrderNumber;
|
||||
$this->purchaseOrderDate = $purchaseOrderDate;
|
||||
$this->items = $items;
|
||||
$this->sellingParty = $sellingParty;
|
||||
$this->warehouseId = $warehouseId;
|
||||
$this->shipToParty = $shipToParty;
|
||||
$this->shipmentDetails = $shipmentDetails;
|
||||
$this->rawData = $rawData;
|
||||
}
|
||||
|
||||
/** @return string */
|
||||
public function getPurchaseOrderNumber(): string
|
||||
{
|
||||
return $this->purchaseOrderNumber;
|
||||
}
|
||||
|
||||
/** @return DateTime|false */
|
||||
public function getPurchaseOrderDate()
|
||||
{
|
||||
return $this->purchaseOrderDate;
|
||||
}
|
||||
|
||||
/** @return array|PurchaseOrderItem[] */
|
||||
public function getItems()
|
||||
{
|
||||
return $this->items;
|
||||
}
|
||||
|
||||
/** @return SellingParty */
|
||||
public function getSellingParty(): SellingParty
|
||||
{
|
||||
return $this->sellingParty;
|
||||
}
|
||||
|
||||
public function getShipToParty(): Address
|
||||
{
|
||||
return $this->shipToParty;
|
||||
}
|
||||
|
||||
public function getShipmentDetails(): ShipmentDetails
|
||||
{
|
||||
return $this->shipmentDetails;
|
||||
}
|
||||
|
||||
public function getRawData(): array
|
||||
{
|
||||
return $this->rawData;
|
||||
}
|
||||
|
||||
public static function fromPurchaseOrderResponse(array $data)
|
||||
{
|
||||
if (isset($data['payload'])) {
|
||||
$data = $data['payload'];
|
||||
}
|
||||
|
||||
$items = array_map(
|
||||
function (array $item) {
|
||||
return PurchaseOrderItem::fromPurchaseOrderResponse($item);
|
||||
},
|
||||
$data['orderDetails']['items']
|
||||
);
|
||||
|
||||
$sellingParty = new SellingParty($data['orderDetails']['sellingParty']['partyId']);
|
||||
$shipToParty = (new Address())
|
||||
->setName($data['orderDetails']['shipToParty']['name'])
|
||||
->setAddressLines(
|
||||
[
|
||||
$data['orderDetails']['shipToParty']['addressLine1'],
|
||||
$data['orderDetails']['shipToParty']['addressLine2'],
|
||||
$data['orderDetails']['shipToParty']['addressLine3'],
|
||||
]
|
||||
)
|
||||
->setCity($data['orderDetails']['shipToParty']['city'])
|
||||
->setStateOrRegion($data['orderDetails']['shipToParty']['stateOrRegion'])
|
||||
->setPostalCode($data['orderDetails']['shipToParty']['postalCode'])
|
||||
->setCountryCode($data['orderDetails']['shipToParty']['countryCode']);
|
||||
|
||||
$shipmentDetails = new ShipmentDetails(
|
||||
$data['orderDetails']['shipmentDetails']['isPriorityShipment'],
|
||||
$data['orderDetails']['shipmentDetails']['isPslipRequired'],
|
||||
$data['orderDetails']['shipmentDetails']['shipMethod'],
|
||||
self::parseDate($data['orderDetails']['shipmentDetails']['shipmentDates']['requiredShipDate']),
|
||||
self::parseDate($data['orderDetails']['shipmentDetails']['shipmentDates']['promisedDeliveryDate']),
|
||||
isset($data['orderDetails']['shipmentDetails']['messageToCustomer'])
|
||||
? $data['orderDetails']['shipmentDetails']['messageToCustomer']
|
||||
: ''
|
||||
);
|
||||
|
||||
// @TODO billToParty needs to be set
|
||||
return new static(
|
||||
$data['purchaseOrderNumber'],
|
||||
self::parseDate($data['orderDetails']['orderDate']),
|
||||
$items,
|
||||
$sellingParty,
|
||||
$data['orderDetails']['shipFromParty']['partyId'],
|
||||
$shipToParty,
|
||||
$shipmentDetails,
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
protected static function parseDate(string $iso8601DateString): DateTime
|
||||
{
|
||||
$date = DateTime::createFromFormat(
|
||||
DateTime::ISO8601,
|
||||
$iso8601DateString
|
||||
);
|
||||
|
||||
if(!$date instanceof DateTime){
|
||||
throw new InvalidArgumentException("Date is not in ISO8601 format: {$iso8601DateString}");
|
||||
}
|
||||
|
||||
return $date;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
use DateTime;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\MissingInformationException;
|
||||
|
||||
class PurchaseOrderAcknowledgement
|
||||
{
|
||||
/** @var string */
|
||||
private $vendorOrderNumber;
|
||||
/** @var string */
|
||||
private $purchaseOrderNumber;
|
||||
/** @var SellingParty */
|
||||
private $sellingParty;
|
||||
/** @var Warehouse */
|
||||
private $warehouse;
|
||||
/** @var array|AcknowledgementItem[] */
|
||||
private $items = [];
|
||||
|
||||
public function __construct(string $purchaseOrderNumber)
|
||||
{
|
||||
$this->purchaseOrderNumber = $purchaseOrderNumber;
|
||||
}
|
||||
|
||||
public function getPurchaseOrderNumber(): string
|
||||
{
|
||||
return $this->purchaseOrderNumber;
|
||||
}
|
||||
|
||||
public function addItem(AcknowledgementItem $item): self
|
||||
{
|
||||
$this->items[] = $item;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setVendorOrderNumber(string $vendorOrderNumber): self
|
||||
{
|
||||
$this->vendorOrderNumber = $vendorOrderNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setSellingParty(SellingParty $sellingParty): self
|
||||
{
|
||||
$this->sellingParty = $sellingParty;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setWarehouse(Warehouse $warehouse): self
|
||||
{
|
||||
$this->warehouse = $warehouse;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasRejectedItems(): bool
|
||||
{
|
||||
foreach ($this->items as $item) {
|
||||
if ($item->isRejected()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getStatusCodeOfFirstRejectedItem(): string
|
||||
{
|
||||
foreach ($this->items as $item) {
|
||||
if ($item->isRejected()) {
|
||||
return $item->getStatusCode();
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException('No rejected item found');
|
||||
}
|
||||
|
||||
protected function generateStatus(): array
|
||||
{
|
||||
$statusCode = AcknowledgementItem::CODE_ACCEPTED;
|
||||
if ($this->hasRejectedItems()) {
|
||||
$statusCode = $this->getStatusCodeOfFirstRejectedItem();
|
||||
}
|
||||
|
||||
return [
|
||||
'code' => $statusCode,
|
||||
'description' => AcknowledgementItem::AVAILABLE_CODES[$statusCode],
|
||||
];
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
if (!$this->warehouse) {
|
||||
throw MissingInformationException::property('warehouse');
|
||||
}
|
||||
if ($this->warehouse->hasNoAddress()) {
|
||||
throw MissingInformationException::property('warehouse address');
|
||||
}
|
||||
if (!$this->vendorOrderNumber) {
|
||||
throw MissingInformationException::property('vendorOrderNumber');
|
||||
}
|
||||
|
||||
// Map AcknowledgementItems to array
|
||||
$items = array_map(
|
||||
function (AcknowledgementItem $item) {
|
||||
return $item->toArray();
|
||||
},
|
||||
$this->items
|
||||
);
|
||||
|
||||
$data = [
|
||||
'purchaseOrderNumber' => $this->purchaseOrderNumber,
|
||||
'vendorOrderNumber' => $this->vendorOrderNumber,
|
||||
'acknowledgementDate' => (new DateTime())->format(DateTime::ATOM),
|
||||
'acknowledgementStatus' => $this->generateStatus(),
|
||||
'sellingParty' => $this->sellingParty->toArray(),
|
||||
'shipFromParty' => $this->warehouse->toArray(),
|
||||
'itemAcknowledgements' => $items,
|
||||
];
|
||||
|
||||
// In the PurchaseOrderAcknowledgement endpoint the key
|
||||
// is named taxInfo instead of taxRegistrationDetails
|
||||
$data['sellingParty']['taxInfo'] = $data['sellingParty']['taxRegistrationDetails'];
|
||||
$data['shipFromParty']['taxInfo'] = $data['sellingParty']['taxInfo'];
|
||||
unset($data['sellingParty']['taxRegistrationDetails']);
|
||||
unset($data['sellingParty']['taxInfo']['taxRegistrationAddress']);
|
||||
unset($data['shipFromParty']['taxInfo']['taxRegistrationAddress']);
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class PurchaseOrderItem
|
||||
{
|
||||
/** @var string */
|
||||
private $itemSequenceNumber;
|
||||
/** @var string */
|
||||
private $buyerProductIdentifier;
|
||||
/** @var string */
|
||||
private $vendorProductIdentifier;
|
||||
/** @var string */
|
||||
private $title;
|
||||
/** @var Quantity */
|
||||
private $quantity;
|
||||
/** @var Price */
|
||||
private $price;
|
||||
/** @var float */
|
||||
private $taxRate;
|
||||
|
||||
public function __construct(
|
||||
string $itemSequenceNumber,
|
||||
string $buyerProductIdentifier,
|
||||
string $vendorProductIdentifier,
|
||||
string $title,
|
||||
Quantity $quantity,
|
||||
Price $price,
|
||||
float $taxRate
|
||||
) {
|
||||
$this->itemSequenceNumber = $itemSequenceNumber;
|
||||
$this->buyerProductIdentifier = $buyerProductIdentifier;
|
||||
$this->vendorProductIdentifier = $vendorProductIdentifier;
|
||||
$this->title = $title;
|
||||
$this->quantity = $quantity;
|
||||
$this->price = $price;
|
||||
$this->taxRate = $taxRate;
|
||||
}
|
||||
|
||||
public function getItemSequenceNumber(): string
|
||||
{
|
||||
return $this->itemSequenceNumber;
|
||||
}
|
||||
|
||||
public function getBuyerProductIdentifier(): string
|
||||
{
|
||||
return $this->buyerProductIdentifier;
|
||||
}
|
||||
|
||||
public function getVendorProductIdentifier(): string
|
||||
{
|
||||
return $this->vendorProductIdentifier;
|
||||
}
|
||||
|
||||
public function setVendorProductIdentifier(string $vendorProductIdentifier): void
|
||||
{
|
||||
$this->vendorProductIdentifier = $vendorProductIdentifier;
|
||||
}
|
||||
|
||||
public function getQuantity(): Quantity
|
||||
{
|
||||
return $this->quantity;
|
||||
}
|
||||
|
||||
public function getPrice(): Price
|
||||
{
|
||||
return $this->price;
|
||||
}
|
||||
|
||||
public function getTitle(): string
|
||||
{
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
public function getTaxRate(): float
|
||||
{
|
||||
return $this->taxRate;
|
||||
}
|
||||
|
||||
public function reject(string $code): AcknowledgementItem
|
||||
{
|
||||
return new AcknowledgementItem($this, $code);
|
||||
}
|
||||
|
||||
public function accept(): AcknowledgementItem
|
||||
{
|
||||
return new AcknowledgementItem($this, AcknowledgementItem::CODE_ACCEPTED);
|
||||
}
|
||||
|
||||
public static function fromPurchaseOrderResponse(array $data): self
|
||||
{
|
||||
return new static(
|
||||
$data['itemSequenceNumber'],
|
||||
$data['buyerProductIdentifier'],
|
||||
$data['vendorProductIdentifier'],
|
||||
$data['title'],
|
||||
Quantity::fromArray($data['orderedQuantity']),
|
||||
new Price($data['netPrice']['currencyCode'], $data['netPrice']['amount']),
|
||||
(float)$data['taxDetails']['taxLineItem'][0]['taxRate']
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class Quantity
|
||||
{
|
||||
/** @var int */
|
||||
private $amount;
|
||||
/** @var string */
|
||||
private $unitOfMeasure;
|
||||
/** @var int */
|
||||
private $unitSize;
|
||||
|
||||
public function __construct(int $amount, string $unitOfMeasure = 'Each', ?int $unitSize = 1)
|
||||
{
|
||||
$this->amount = $amount;
|
||||
$this->unitOfMeasure = $unitOfMeasure;
|
||||
$this->unitSize = $unitSize;
|
||||
}
|
||||
|
||||
public function getAmount(): int
|
||||
{
|
||||
return $this->amount;
|
||||
}
|
||||
|
||||
public function getUnitOfMeasure(): string
|
||||
{
|
||||
return $this->unitOfMeasure;
|
||||
}
|
||||
|
||||
public function getUnitSize(): int
|
||||
{
|
||||
return $this->unitSize;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'amount' => $this->amount,
|
||||
'unitOfMeasure' => $this->unitOfMeasure,
|
||||
'unitSize' => $this->unitSize,
|
||||
];
|
||||
}
|
||||
|
||||
public static function fromArray(array $data)
|
||||
{
|
||||
return new static(
|
||||
$data['amount'],
|
||||
$data['unitOfMeasure'],
|
||||
isset($data['unitSize']) ? $data['unitSize'] : null
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class SellingParty
|
||||
{
|
||||
/** @var string */
|
||||
private $partyId;
|
||||
|
||||
/** @var Address */
|
||||
private $address;
|
||||
|
||||
/** @var TaxRegistrationDetails */
|
||||
private $taxRegistrationDetails;
|
||||
|
||||
public function __construct(string $partyId)
|
||||
{
|
||||
$this->partyId = $partyId;
|
||||
}
|
||||
|
||||
public function getPartyId(): string
|
||||
{
|
||||
return $this->partyId;
|
||||
}
|
||||
|
||||
public function getAddress(): Address
|
||||
{
|
||||
return $this->address;
|
||||
}
|
||||
|
||||
public function setAddress(Address $address): self
|
||||
{
|
||||
$this->address = $address;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTaxRegistrationDetails(): TaxRegistrationDetails
|
||||
{
|
||||
return $this->taxRegistrationDetails;
|
||||
}
|
||||
|
||||
public function setTaxRegistrationDetails(TaxRegistrationDetails $taxRegistrationDetails): self
|
||||
{
|
||||
$this->taxRegistrationDetails = $taxRegistrationDetails;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'partyId' => $this->partyId,
|
||||
'address' => $this->address->toArray(),
|
||||
'taxRegistrationDetails' => $this->taxRegistrationDetails->toArray()
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class ShipmentConfirmation extends ShippingLabelRequest
|
||||
{
|
||||
public function toArray()
|
||||
{
|
||||
$data = [
|
||||
'purchaseOrderNumber' => $this->purchaseOrderNumber,
|
||||
'sellingParty' => $this->sellingParty->toArray(),
|
||||
'shipmentDetails' => [
|
||||
'shippedDate' => (new \DateTime('now'))->format(DATE_ATOM),
|
||||
'shipmentStatus' => 'SHIPPED'
|
||||
],
|
||||
'shipFromParty' => $this->warehouse->toArray(),
|
||||
'items' => $this->extractItemsFromContainers(),
|
||||
'containers' => array_map(
|
||||
function (Container $container) {
|
||||
return $container->toArray();
|
||||
},
|
||||
$this->containers
|
||||
),
|
||||
];
|
||||
|
||||
$data['sellingParty']['taxRegistrationDetails'] = [$data['sellingParty']['taxRegistrationDetails']];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract all items form the single containers because they are
|
||||
* needed in the top level of the shipment confirmation as well.
|
||||
*/
|
||||
private function extractItemsFromContainers(): array
|
||||
{
|
||||
$items = [];
|
||||
|
||||
foreach ($this->containers as $container) {
|
||||
$items = array_merge($items, $container->getItems());
|
||||
}
|
||||
|
||||
return array_map(
|
||||
function (array $item) {
|
||||
// In the items of the shipmentConfirmation the key is
|
||||
// called shippedQuantity instead of packedQuantity
|
||||
$item['shippedQuantity'] = $item['packedQuantity'];
|
||||
unset($item['packedQuantity']);
|
||||
|
||||
return $item;
|
||||
},
|
||||
$items
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class ShipmentDetails
|
||||
{
|
||||
/** @var bool */
|
||||
private $isPriorityShipment;
|
||||
/** @var bool */
|
||||
private $isPslipRequired;
|
||||
/** @var string */
|
||||
private $shipMethod;
|
||||
/** @var DateTime */
|
||||
private $promisedDeliveryDate;
|
||||
/** @var DateTime */
|
||||
private $requiredShipDate;
|
||||
/** @var string */
|
||||
private $messageToCustomer;
|
||||
|
||||
public function __construct(
|
||||
bool $isPriorityShipment,
|
||||
bool $isPslipRequired,
|
||||
string $shipMethod,
|
||||
DateTime $requiredShipDate,
|
||||
DateTime $promisedDeliveryDate,
|
||||
string $messageToCustomer
|
||||
) {
|
||||
$this->isPriorityShipment = $isPriorityShipment;
|
||||
$this->isPslipRequired = $isPslipRequired;
|
||||
$this->shipMethod = $shipMethod;
|
||||
$this->requiredShipDate = $requiredShipDate;
|
||||
$this->promisedDeliveryDate = $promisedDeliveryDate;
|
||||
$this->messageToCustomer = $messageToCustomer;
|
||||
}
|
||||
|
||||
public function isPriorityShipment(): bool
|
||||
{
|
||||
return $this->isPriorityShipment;
|
||||
}
|
||||
|
||||
public function isPslipRequired(): bool
|
||||
{
|
||||
return $this->isPslipRequired;
|
||||
}
|
||||
|
||||
|
||||
public function getShipMethod(): string
|
||||
{
|
||||
return $this->shipMethod;
|
||||
}
|
||||
|
||||
public function getRequiredShipDate(): DateTime
|
||||
{
|
||||
return $this->requiredShipDate;
|
||||
}
|
||||
|
||||
public function getPromisedDeliveryDate(): DateTime
|
||||
{
|
||||
return $this->promisedDeliveryDate;
|
||||
}
|
||||
|
||||
public function getMessageToCustomer(): string
|
||||
{
|
||||
return $this->messageToCustomer;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class ShippingLabel implements \JsonSerializable
|
||||
{
|
||||
/** @var string */
|
||||
private $purchaseOrderNumber;
|
||||
/** @var string */
|
||||
private $encodedLabelData;
|
||||
/** @var string */
|
||||
private $labelFormat;
|
||||
/** @var string */
|
||||
private $trackingNumber;
|
||||
|
||||
public function __construct(string $purchaseOrderNumber, string $encodedLabelData, string $labelFormat = 'PNG')
|
||||
{
|
||||
//@TODO check if we need to implement multiple labels per order
|
||||
$this->purchaseOrderNumber = $purchaseOrderNumber;
|
||||
$this->encodedLabelData = $encodedLabelData;
|
||||
$this->labelFormat = $labelFormat;
|
||||
}
|
||||
|
||||
public function getTrackingNumber(): string
|
||||
{
|
||||
return $this->trackingNumber;
|
||||
}
|
||||
|
||||
public function setTrackingNumber(string $trackingNumber): self
|
||||
{
|
||||
$this->trackingNumber = $trackingNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasTrackingNumber(): bool
|
||||
{
|
||||
return $this->trackingNumber !== null;
|
||||
}
|
||||
|
||||
public function getEncodedLabelData(): string
|
||||
{
|
||||
return $this->encodedLabelData;
|
||||
}
|
||||
|
||||
public function jsonSerialize(): array
|
||||
{
|
||||
return [
|
||||
'purchase_order_number' => $this->purchaseOrderNumber,
|
||||
'tracking_number' => $this->trackingNumber,
|
||||
'encodedLabelData' => $this->encodedLabelData
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class ShippingLabelRequest
|
||||
{
|
||||
/** @var string */
|
||||
protected $purchaseOrderNumber;
|
||||
/** @var SellingParty */
|
||||
protected $sellingParty;
|
||||
/** @var Warehouse */
|
||||
protected $warehouse;
|
||||
/** @var array|Container[] */
|
||||
protected $containers = [];
|
||||
|
||||
public function __construct(string $purchaseOrderNumber, SellingParty $sellingParty, Warehouse $warehouse)
|
||||
{
|
||||
$this->purchaseOrderNumber = $purchaseOrderNumber;
|
||||
$this->sellingParty = $sellingParty;
|
||||
$this->warehouse = $warehouse;
|
||||
}
|
||||
|
||||
public function addContainer(Container $container)
|
||||
{
|
||||
$this->containers[] = $container;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'purchaseOrderNumber' => $this->purchaseOrderNumber,
|
||||
'sellingParty' => [
|
||||
'partyId' => $this->sellingParty->getPartyId()
|
||||
],
|
||||
'shipFromParty' => [
|
||||
'partyId' => $this->warehouse->getWarehouseId()
|
||||
],
|
||||
'containers' => array_map(
|
||||
function (Container $container) {
|
||||
return $container->toArray();
|
||||
},
|
||||
$this->containers
|
||||
),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class TaxDetails
|
||||
{
|
||||
/** @var string */
|
||||
private $taxType;
|
||||
/** @var string */
|
||||
private $taxRate;
|
||||
/** @var Price */
|
||||
private $taxAmount;
|
||||
/** @var Price */
|
||||
private $taxableAmount;
|
||||
|
||||
public function __construct(string $taxType, string $taxRate, Price $taxAmount, Price $taxableAmount)
|
||||
{
|
||||
$this->taxType = $taxType;
|
||||
$this->taxRate = $taxRate;
|
||||
$this->taxAmount = $taxAmount;
|
||||
$this->taxableAmount = $taxableAmount;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'taxType' => $this->taxType,
|
||||
'taxRate' => $this->taxRate,
|
||||
'taxAmount' => $this->taxAmount->toArray(),
|
||||
'taxableAmount' => $this->taxableAmount->toArray(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class TaxRegistrationDetails
|
||||
{
|
||||
/** @var string */
|
||||
private $taxRegistrationType;
|
||||
/** @var string */
|
||||
private $taxRegistrationNumber;
|
||||
/** @var Address */
|
||||
private $taxRegistrationAddress;
|
||||
|
||||
public function getTaxRegistrationType(): string
|
||||
{
|
||||
return $this->taxRegistrationType;
|
||||
}
|
||||
|
||||
public function setTaxRegistrationType(string $taxRegistrationType): self
|
||||
{
|
||||
$this->taxRegistrationType = $taxRegistrationType;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTaxRegistrationNumber(): string
|
||||
{
|
||||
return $this->taxRegistrationNumber;
|
||||
}
|
||||
|
||||
public function setTaxRegistrationNumber(string $taxRegistrationNumber): self
|
||||
{
|
||||
$this->taxRegistrationNumber = $taxRegistrationNumber;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTaxRegistrationAddress(): Address
|
||||
{
|
||||
return $this->taxRegistrationAddress;
|
||||
}
|
||||
|
||||
public function setTaxRegistrationAddress(Address $taxRegistrationAddress): self
|
||||
{
|
||||
$this->taxRegistrationAddress = $taxRegistrationAddress;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'taxRegistrationType' => $this->taxRegistrationType,
|
||||
'taxRegistrationNumber' => $this->taxRegistrationNumber,
|
||||
'taxRegistrationAddress' => $this->taxRegistrationAddress->toArray(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class Token
|
||||
{
|
||||
/** @var string */
|
||||
private $accessToken;
|
||||
|
||||
/** @var string */
|
||||
private $refreshToken;
|
||||
|
||||
/** @var DateTimeImmutable */
|
||||
private $expirationDate;
|
||||
|
||||
public function __construct(string $accessToken, string $refreshToken, int $expiresInSeconds = 3600)
|
||||
{
|
||||
$this->accessToken = $accessToken;
|
||||
$this->refreshToken = $refreshToken;
|
||||
$this->expirationDate = new DateTimeImmutable( "+{$expiresInSeconds} seconds");
|
||||
}
|
||||
|
||||
public function getAccessToken(): string
|
||||
{
|
||||
return $this->accessToken;
|
||||
}
|
||||
|
||||
public function getRefreshToken(): string
|
||||
{
|
||||
return $this->refreshToken;
|
||||
}
|
||||
|
||||
public function isExpired(): bool
|
||||
{
|
||||
return new DateTime('now') > $this->expirationDate;
|
||||
}
|
||||
|
||||
public static function fromResponse(ResponseInterface $response): self
|
||||
{
|
||||
$tokenInformation = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
return new static($tokenInformation['access_token'], $tokenInformation['refresh_token'], $tokenInformation['expires_in']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
use DateTime;
|
||||
|
||||
class Transaction
|
||||
{
|
||||
const STATUS_FAILURE = 'Failure';
|
||||
const STATUS_PROCESSING = 'Processing';
|
||||
const STATUS_SUCCESS = 'Success';
|
||||
const STATUS_WAITING = 'Waiting';
|
||||
const STATUS_CLOSED = 'Closed';
|
||||
|
||||
/** @var int */
|
||||
private $id;
|
||||
/** @var string */
|
||||
private $externalId;
|
||||
/** @var string */
|
||||
private $subject;
|
||||
/** @var string */
|
||||
private $subject_id;
|
||||
/** @var string */
|
||||
private $status;
|
||||
/** @var array */
|
||||
private $errors;
|
||||
/** @var DateTime */
|
||||
private $created_at;
|
||||
/** @var DateTime */
|
||||
private $updated_at;
|
||||
|
||||
|
||||
public function __construct(string $subject = '')
|
||||
{
|
||||
$this->subject = $subject;
|
||||
}
|
||||
|
||||
public function isWaiting(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_WAITING;
|
||||
}
|
||||
|
||||
public function isProcessing(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_PROCESSING;
|
||||
}
|
||||
|
||||
public function hasFailed(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_FAILURE;
|
||||
}
|
||||
|
||||
public function hasSucceeded(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function setId(int $id): self
|
||||
{
|
||||
$this->id = $id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getExternalId(): ?string
|
||||
{
|
||||
return $this->externalId;
|
||||
}
|
||||
|
||||
public function setExternalId(string $externalId): self
|
||||
{
|
||||
$this->externalId = $externalId;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubject(): string
|
||||
{
|
||||
return $this->subject;
|
||||
}
|
||||
|
||||
public function setSubject(string $subject): self
|
||||
{
|
||||
$this->subject = $subject;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSubjectId(): ?string
|
||||
{
|
||||
return $this->subject_id;
|
||||
}
|
||||
|
||||
public function setSubjectId(string $subject_id): self
|
||||
{
|
||||
$this->subject_id = $subject_id;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
public function setStatus(string $status): self
|
||||
{
|
||||
$this->status = $status;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getErrors(): array
|
||||
{
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
public function setErrors(array $errors): self
|
||||
{
|
||||
$this->errors = $errors;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTime
|
||||
{
|
||||
return $this->created_at;
|
||||
}
|
||||
|
||||
public function setCreatedAt(DateTime $created_at): self
|
||||
{
|
||||
$this->created_at = $created_at;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): DateTime
|
||||
{
|
||||
return $this->updated_at;
|
||||
}
|
||||
|
||||
public function setUpdatedAt(DateTime $updated_at): self
|
||||
{
|
||||
$this->updated_at = $updated_at;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Data;
|
||||
|
||||
class Warehouse
|
||||
{
|
||||
/** @var string */
|
||||
private $warehouseId;
|
||||
/** @var Address */
|
||||
private $address;
|
||||
|
||||
public function __construct(string $warehouseId)
|
||||
{
|
||||
$this->warehouseId = $warehouseId;
|
||||
}
|
||||
|
||||
public function setAddress(Address $address): self
|
||||
{
|
||||
$this->address = $address;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasNoAddress(): bool
|
||||
{
|
||||
return $this->address === null;
|
||||
}
|
||||
|
||||
public function getWarehouseId(): string
|
||||
{
|
||||
return $this->warehouseId;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return [
|
||||
'partyId' => $this->warehouseId,
|
||||
'address' => $this->address->toArray(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Exception;
|
||||
|
||||
class ColumnNotFoundException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Exception;
|
||||
|
||||
class DuplicatePurchaseOrderException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Exception;
|
||||
|
||||
use Exception;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\AcknowledgementItem;
|
||||
|
||||
class InvalidAcknowledgementCodeException extends Exception
|
||||
{
|
||||
public static function invalidCode(string $code)
|
||||
{
|
||||
return new static(
|
||||
"Invalid acknowledgement code \"{$code}\". Hast to be one of: \n" . implode(
|
||||
"\n",
|
||||
AcknowledgementItem::AVAILABLE_CODES
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
public static function missingCode(string $code)
|
||||
{
|
||||
return new static(
|
||||
'Acknowledgement is not accepted nor rejected. You have to call accept() or reject()'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Exception;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use RuntimeException;
|
||||
|
||||
class IssueTokenException extends RuntimeException
|
||||
{
|
||||
public static function fromResponse(?ResponseInterface $response = null): self
|
||||
{
|
||||
return new self($response ? 'exception with response info' : 'exception without response info');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Exception;
|
||||
|
||||
use Exception;
|
||||
|
||||
class MissingInformationException extends Exception
|
||||
{
|
||||
public static function property(string $property)
|
||||
{
|
||||
return new static("\"{$property}\" is not set!");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Exception;
|
||||
|
||||
class PurchaseOrderNumberNotFoundException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Exception;
|
||||
|
||||
class TransferException extends \RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Models;
|
||||
|
||||
use DateTime;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\PurchaseOrder;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\ShippingLabel;
|
||||
|
||||
class PurchaseOrderInformation
|
||||
{
|
||||
/** Step 1: Purchase order resulted in an entry in the database which was not processed yet */
|
||||
public const STATUS_UNPROCESSED = null;
|
||||
/** Step 2: Purchase order resulted in an order but was not acknowledged yet */
|
||||
public const STATUS_PROCESSING = 'processing';
|
||||
|
||||
/** Step 3: Acknowledgement was sent, but it was not yet cleared by Amazon */
|
||||
public const STATUS_ACKNOWLEDGEMENT_SENT = 'acknowledgement_sent';
|
||||
/** Step 3b: Purchase could not be processed automatically and requires user input */
|
||||
public const STATUS_WAITING_FOR_USER_INPUT = 'waiting_for_user_input';
|
||||
/** Step 3c: There was an error on the remote end preventing the acknowledgement from being processed*/
|
||||
public const STATUS_ACKNOWLEDGEMENT_FAILED = 'acknowledgement_failed';
|
||||
/** Step 4: Acknowledgement was accepted by Amazon */
|
||||
public const STATUS_ACKNOWLEDGEMENT_ACCEPTED = 'acknowledgement_accepted';
|
||||
/** Step 4b: Acknowledgement was rejected by amazon */
|
||||
public const STATUS_ACKNOWLEDGEMENT_REJECTED = 'acknowledgement_rejected';
|
||||
|
||||
/** Step 5: Shipping label was requested, but not yet provided by Amazon */
|
||||
public const STATUS_SHIPPING_LABEL_REQUESTED = 'shipping_label_requested';
|
||||
/** Step 6: Shipping label request was successful and can be downloaded */
|
||||
public const STATUS_SHIPPING_LABEL_ACCEPTED = 'shipping_label_accepted';
|
||||
/** Step 6b: Shipping label request was rejected by amazon */
|
||||
public const STATUS_SHIPPING_LABEL_REJECTED = 'shipping_label_rejected';
|
||||
|
||||
/** Step 7: */
|
||||
public const STATUS_SHIPMENT_CONFIRMATION_SENT = 'shipment_confirmation_sent';
|
||||
|
||||
/** Rejected by user input */
|
||||
public const STATUS_REJECTED_BY_USER_INPUT = 'rejected_by_user_input';
|
||||
|
||||
/** @var string */
|
||||
private $externalId;
|
||||
/** @var string */
|
||||
private $raw;
|
||||
/** @var null|int */
|
||||
private $orderId;
|
||||
/** @var bool */
|
||||
private $acknowledged = false;
|
||||
/** @var null|string */
|
||||
private $acknowledgementTransactionId;
|
||||
/** @var bool */
|
||||
private $shippingLabelRequested = false;
|
||||
/** @var null|string */
|
||||
private $shippingLabelRequestTransactionId;
|
||||
/** @var null|string */
|
||||
private $shippingLabelData;
|
||||
/** @var DateTime|null */
|
||||
private $createdAt;
|
||||
/** @var Datetime|null */
|
||||
private $updatedAt;
|
||||
/** @var string */
|
||||
private $status;
|
||||
/** @var string */
|
||||
private $shipmentConfirmationTransactionId;
|
||||
|
||||
public function __construct(string $externalId)
|
||||
{
|
||||
$this->externalId = $externalId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|string
|
||||
*/
|
||||
public function getShipmentConfirmationTransactionId(): ?string
|
||||
{
|
||||
return $this->shipmentConfirmationTransactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $shipmentConfirmationTransactionId
|
||||
*/
|
||||
public function setShipmentConfirmationTransactionId(string $shipmentConfirmationTransactionId): void
|
||||
{
|
||||
$this->shipmentConfirmationTransactionId = $shipmentConfirmationTransactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function wasShipmentConfirmationSent(): bool
|
||||
{
|
||||
return $this->shipmentConfirmationTransactionId !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getStatus(): ?string
|
||||
{
|
||||
return $this->status;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $status
|
||||
*/
|
||||
public function setStatus(string $status): void
|
||||
{
|
||||
$this->status = $status;
|
||||
}
|
||||
|
||||
public function canFetchShippingLabels(): bool
|
||||
{
|
||||
return $this->status === self::STATUS_SHIPPING_LABEL_ACCEPTED
|
||||
|| (empty($this->shippingLabelData) && $this->status === self::STATUS_SHIPMENT_CONFIRMATION_SENT);
|
||||
}
|
||||
|
||||
public function hasShippingLabel(): bool
|
||||
{
|
||||
return $this->shippingLabelData !== null;
|
||||
}
|
||||
|
||||
public function getPurchaseOrderNumber(): string
|
||||
{
|
||||
return $this->externalId;
|
||||
}
|
||||
|
||||
public function getRawJson(): ?string
|
||||
{
|
||||
return $this->raw;
|
||||
}
|
||||
|
||||
public function getOrderId(): ?int
|
||||
{
|
||||
return $this->orderId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int|null $orderId
|
||||
*/
|
||||
public function setOrderId(?int $orderId): void
|
||||
{
|
||||
$this->orderId = $orderId;
|
||||
}
|
||||
|
||||
public function isAcknowledged(): bool
|
||||
{
|
||||
return $this->acknowledged;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $acknowledged
|
||||
*/
|
||||
public function setAcknowledged(bool $acknowledged): void
|
||||
{
|
||||
$this->acknowledged = $acknowledged;
|
||||
}
|
||||
|
||||
public function getAcknowledgementTransactionId(): ?string
|
||||
{
|
||||
return $this->acknowledgementTransactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $acknowledgementTransactionId
|
||||
*/
|
||||
public function setAcknowledgementTransactionId(?string $acknowledgementTransactionId): void
|
||||
{
|
||||
$this->acknowledgementTransactionId = $acknowledgementTransactionId;
|
||||
}
|
||||
|
||||
public function isShippingLabelRequested(): bool
|
||||
{
|
||||
return $this->shippingLabelRequested;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param bool $shippingLabelRequested
|
||||
*/
|
||||
public function setShippingLabelRequested(bool $shippingLabelRequested): void
|
||||
{
|
||||
$this->shippingLabelRequested = $shippingLabelRequested;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getExternalId(): string
|
||||
{
|
||||
return $this->externalId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
*/
|
||||
public function getShippingLabelRequestTransactionId(): ?string
|
||||
{
|
||||
return $this->shippingLabelRequestTransactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $shippingLabelRequestTransactionId
|
||||
*/
|
||||
public function setShippingLabelRequestTransactionId(?string $shippingLabelRequestTransactionId): void
|
||||
{
|
||||
$this->shippingLabelRequestTransactionId = $shippingLabelRequestTransactionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ShippingLabel[]
|
||||
*/
|
||||
public function getShippingLabels(): array
|
||||
{
|
||||
$decodedShippingLabels = json_decode($this->shippingLabelData, true);
|
||||
|
||||
return array_map(
|
||||
function (array $data) {
|
||||
$shippingLabel = new ShippingLabel(
|
||||
$data['purchase_order_number'],
|
||||
$data['encodedLabelData']
|
||||
);
|
||||
$shippingLabel->setTrackingNumber($data['tracking_number']);
|
||||
|
||||
return $shippingLabel;
|
||||
},
|
||||
$decodedShippingLabels
|
||||
);
|
||||
}
|
||||
|
||||
public function setShippingLabels(array $shippingLabels): void
|
||||
{
|
||||
$this->shippingLabelData = json_encode($shippingLabels);
|
||||
}
|
||||
|
||||
public function getShippingLabelData(): ?string
|
||||
{
|
||||
return $this->shippingLabelData;
|
||||
}
|
||||
|
||||
public function setShippingLabelData(string $shippingLabelData): void
|
||||
{
|
||||
$this->shippingLabelData = $shippingLabelData;
|
||||
}
|
||||
|
||||
public function setRaw(string $raw): void
|
||||
{
|
||||
$this->raw = $raw;
|
||||
}
|
||||
|
||||
public function getPurchaseOrder(): PurchaseOrder
|
||||
{
|
||||
return PurchaseOrder::fromPurchaseOrderResponse(json_decode($this->raw, true));
|
||||
}
|
||||
|
||||
public function getCreatedAt(): ?DateTime
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime $createdAt
|
||||
*/
|
||||
public function setCreatedAt(DateTime $createdAt): void
|
||||
{
|
||||
$this->createdAt = $createdAt;
|
||||
}
|
||||
|
||||
public function getUpdatedAt(): ?DateTime
|
||||
{
|
||||
return $this->updatedAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Datetime $updatedAt
|
||||
*/
|
||||
public function setUpdatedAt(Datetime $updatedAt): void
|
||||
{
|
||||
$this->updatedAt = $updatedAt;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF;
|
||||
|
||||
use Xentral\Components\Database\Database;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\PurchaseOrder;
|
||||
use Xentral\Modules\AmazonVendorDF\Models\PurchaseOrderInformation;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\ColumnNotFoundException;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\DuplicatePurchaseOrderException;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\PurchaseOrderNumberNotFoundException;
|
||||
|
||||
class PurchaseOrderInformationRepository
|
||||
{
|
||||
/** @var string */
|
||||
private $tableName = 'amazon_vendor_df_purchase_orders';
|
||||
|
||||
private $columns = [
|
||||
'status',
|
||||
'external_id',
|
||||
'raw',
|
||||
'order_id',
|
||||
'acknowledged',
|
||||
'acknowledgement_transaction_id',
|
||||
'shipping_label_requested',
|
||||
'shipping_label_request_transaction_id',
|
||||
'shipping_label_data',
|
||||
'shipment_confirmation_transaction_id',
|
||||
'created_at',
|
||||
'updated_at',
|
||||
'shopexport_id',
|
||||
];
|
||||
|
||||
/** @var Database */
|
||||
private $database;
|
||||
|
||||
public function __construct(Database $database)
|
||||
{
|
||||
$this->database = $database;
|
||||
}
|
||||
|
||||
public function createPurchaseOrderInformation(PurchaseOrder $purchaseOrder, int $shopExportId):void
|
||||
{
|
||||
if ($this->doesPurchaseOrderInformationExist($purchaseOrder->getPurchaseOrderNumber())) {
|
||||
throw new DuplicatePurchaseOrderException();
|
||||
}
|
||||
|
||||
$statement = $this->database
|
||||
->insert()
|
||||
->into($this->tableName)
|
||||
->cols(['external_id', 'raw', 'shopexport_id'])
|
||||
->getStatement();
|
||||
|
||||
|
||||
|
||||
$values = [
|
||||
'external_id' => $purchaseOrder->getPurchaseOrderNumber(),
|
||||
'raw' => json_encode($purchaseOrder->getRawData()),
|
||||
'shopexport_id' => json_encode($shopExportId),
|
||||
];
|
||||
$this->database->perform($statement, $values);
|
||||
}
|
||||
|
||||
public function doesPurchaseOrderInformationExist(string $purchaseOrderNumber): bool
|
||||
{
|
||||
$statement = $this->database
|
||||
->select()
|
||||
->cols(['id'])
|
||||
->from($this->tableName)
|
||||
->where('external_id = :external_id')
|
||||
->bindValue('external_id', $purchaseOrderNumber)
|
||||
->limit(1);
|
||||
|
||||
$purchaseOrderId = $this->database->fetchRow($statement->getStatement(), $statement->getBindValues());
|
||||
|
||||
return !empty($purchaseOrderId['id']);
|
||||
}
|
||||
|
||||
public function countPurchaseOrdersWaitingForImport(int $shopExportId): int
|
||||
{
|
||||
$statement = $this->database
|
||||
->select()
|
||||
->cols(['id'])
|
||||
->from($this->tableName)
|
||||
->where('shopexport_id = :shopexport_id')
|
||||
->where('acknowledged = 0')
|
||||
->where('status IS NULL')
|
||||
->bindValue('shopexport_id', $shopExportId);
|
||||
|
||||
return count($this->database->fetchAssoc($statement->getStatement(), $statement->getBindValues()));
|
||||
}
|
||||
|
||||
public function getNextPurchaseOrderInformationToImport(int $shopExportId): PurchaseOrderInformation
|
||||
{
|
||||
$statement = $this->database
|
||||
->select()
|
||||
->cols($this->columns)
|
||||
->from($this->tableName)
|
||||
->where('shopexport_id = :shopexport_id')
|
||||
->where('acknowledged = 0')
|
||||
->where('status IS NULL') //TODO Konstante verwenden
|
||||
->bindValue('shopexport_id', $shopExportId)
|
||||
->orderBy(['created_at ASC'])
|
||||
->limit(1);
|
||||
|
||||
$data = $this->database->fetchRow($statement->getStatement(), $statement->getBindValues());
|
||||
|
||||
return $this->buildPurchaseOrderInformation($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $constraints
|
||||
*
|
||||
* @return PurchaseOrderInformation[]
|
||||
*/
|
||||
public function listPurchaseOrderInformation(array $constraints = []): array
|
||||
{
|
||||
$statement = $this->database
|
||||
->select()
|
||||
->cols($this->columns)
|
||||
->from($this->tableName);
|
||||
|
||||
foreach ($constraints as $constraint) {
|
||||
$column = $constraint[0];
|
||||
if(!in_array($column,$this->columns, false)){
|
||||
throw new ColumnNotFoundException("Column '{$column}' does not exist in table {$this->tableName}");
|
||||
}
|
||||
$value = $constraint[1];
|
||||
if ($value === null) {
|
||||
$statement->where("{$column} IS NULL");
|
||||
continue;
|
||||
}
|
||||
|
||||
$operator = empty($constraint[2]) ? '=' : $constraint[2];
|
||||
|
||||
if ($constraint[1] instanceof \DateTime) {
|
||||
$statement->where("{$column} {$operator} :{$column}");
|
||||
$statement->bindValue($column, $value->format('Y-m-d H:i:s'));
|
||||
} else {
|
||||
$statement->where("{$column} {$operator} :{$column}");
|
||||
$statement->bindValue($column, $value);
|
||||
}
|
||||
}
|
||||
|
||||
return array_map(
|
||||
function (array $data) {
|
||||
return $this->buildPurchaseOrderInformation($data);
|
||||
},
|
||||
$this->database->fetchAll($statement->getStatement(), $statement->getBindValues())
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
public function savePurchaseOrderInformation(PurchaseOrderInformation $purchaseOrderInformation): PurchaseOrderInformation
|
||||
{
|
||||
if (empty($purchaseOrderInformation->getPurchaseOrderNumber())) {
|
||||
//TODO Throw
|
||||
}
|
||||
|
||||
$columnsToSave = [];
|
||||
$columnsToIgnore = ['raw', 'created_at', 'updated_at', 'shopexport_id'];
|
||||
foreach ($this->columns as $column){
|
||||
if(!in_array($column,$columnsToIgnore)){
|
||||
$columnsToSave[] = $column;
|
||||
}
|
||||
}
|
||||
|
||||
$statement = $this->database
|
||||
->update()
|
||||
->cols($columnsToSave)
|
||||
->table($this->tableName)
|
||||
->where('external_id = :external_id')
|
||||
->bindValue('external_id', $purchaseOrderInformation->getPurchaseOrderNumber())
|
||||
->bindValues(
|
||||
[
|
||||
'order_id' => $purchaseOrderInformation->getOrderId(),
|
||||
'status' => $purchaseOrderInformation->getStatus(),
|
||||
'acknowledged' => $purchaseOrderInformation->isAcknowledged(),
|
||||
'acknowledgement_transaction_id' => $purchaseOrderInformation->getAcknowledgementTransactionId(),
|
||||
'shipping_label_requested' => $purchaseOrderInformation->isShippingLabelRequested(),
|
||||
'shipping_label_request_transaction_id' => $purchaseOrderInformation->getShippingLabelRequestTransactionId(),
|
||||
'shipping_label_data' => $purchaseOrderInformation->getShippingLabelData(),
|
||||
'shipment_confirmation_transaction_id' => $purchaseOrderInformation->getShipmentConfirmationTransactionId(),
|
||||
]
|
||||
);
|
||||
|
||||
$this->database->perform($statement, $statement->getBindValues());
|
||||
|
||||
$purchaseOrderInformation->setUpdatedAt(new \DateTime());
|
||||
|
||||
return $purchaseOrderInformation;
|
||||
}
|
||||
|
||||
|
||||
public function getPurchaseOrderInformationByPurchaseOrderNumber(string $purchaseOrderNumber): PurchaseOrderInformation
|
||||
{
|
||||
$statement = $this->database
|
||||
->select()
|
||||
->cols($this->columns)
|
||||
->from($this->tableName)
|
||||
->where('external_id = :external_id')
|
||||
->bindValue('external_id', $purchaseOrderNumber)
|
||||
->limit(1);
|
||||
|
||||
$purchaseOrderData = $this->database->fetchRow($statement->getStatement(), $statement->getBindValues());
|
||||
|
||||
return $this->buildPurchaseOrderInformation($purchaseOrderData);
|
||||
}
|
||||
|
||||
public function getPurchaseOrderInformationByOrderId(int $orderId): PurchaseOrderInformation
|
||||
{
|
||||
$statement = $this->database
|
||||
->select()
|
||||
->cols($this->columns)
|
||||
->from($this->tableName)
|
||||
->where('order_id = :order_id')
|
||||
->bindValue('order_id', $orderId)
|
||||
->limit(1);
|
||||
|
||||
$purchaseOrderData = $this->database->fetchRow($statement->getStatement(), $statement->getBindValues());
|
||||
|
||||
return $this->buildPurchaseOrderInformation($purchaseOrderData);
|
||||
}
|
||||
|
||||
private function buildPurchaseOrderInformation(array $data): PurchaseOrderInformation
|
||||
{
|
||||
if(empty($data['external_id'])){
|
||||
throw new PurchaseOrderNumberNotFoundException();
|
||||
}
|
||||
|
||||
$purchaseOrderStatus = new PurchaseOrderInformation($data['external_id']);
|
||||
if (isset($data['raw'])) {
|
||||
$purchaseOrderStatus->setRaw($data['raw']);
|
||||
}
|
||||
if (isset($data['order_id'])) {
|
||||
$purchaseOrderStatus->setOrderId($data['order_id']);
|
||||
}
|
||||
if (isset($data['acknowledged'])) {
|
||||
$purchaseOrderStatus->setAcknowledged((bool)$data['acknowledged']);
|
||||
}
|
||||
if (isset($data['acknowledgement_transaction_id'])) {
|
||||
$purchaseOrderStatus->setAcknowledgementTransactionId($data['acknowledgement_transaction_id']);
|
||||
}
|
||||
if (isset($data['shipping_label_requested'])) {
|
||||
$purchaseOrderStatus->setShippingLabelRequested((bool)$data['shipping_label_requested']);
|
||||
}
|
||||
if (isset($data['shipping_label_request_transaction_id'])) {
|
||||
$purchaseOrderStatus->setShippingLabelRequestTransactionId($data['shipping_label_request_transaction_id']);
|
||||
}
|
||||
if (isset($data['shipping_label_data'])) {
|
||||
$purchaseOrderStatus->setShippingLabelData($data['shipping_label_data']);
|
||||
}
|
||||
if (isset($data['shipment_confirmation_transaction_id'])) {
|
||||
$purchaseOrderStatus->setAcknowledged($data['shipment_confirmation_transaction_id']);
|
||||
}
|
||||
if (isset($data['created_at'])) {
|
||||
$purchaseOrderStatus->setCreatedAt(\DateTime::createFromFormat('Y-m-d H:i:s', $data['created_at']));
|
||||
}
|
||||
if (isset($data['updated_at'])) {
|
||||
$purchaseOrderStatus->setUpdatedAt(\DateTime::createFromFormat('Y-m-d H:i:s', $data['updated_at']));
|
||||
}
|
||||
if (isset($data['status'])) {
|
||||
$purchaseOrderStatus->setStatus($data['status']);
|
||||
}
|
||||
|
||||
return $purchaseOrderStatus;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Service;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\InventoryItem;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Transaction;
|
||||
|
||||
class InventoryService
|
||||
{
|
||||
/** @var ClientInterface */
|
||||
private $client;
|
||||
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
public function updateInventory(string $warehouseId, array $items, string $sellingPartyId, bool $isFullUpdate = false)
|
||||
{
|
||||
//First map all InventoryItems to an array
|
||||
$items = array_map(
|
||||
function (InventoryItem $item) {
|
||||
$data = $item->toArray();
|
||||
unset($data['availableQuantity']['unitSize']);
|
||||
|
||||
return $data;
|
||||
},
|
||||
$items
|
||||
);
|
||||
|
||||
$response = $this->client->request(
|
||||
'POST',
|
||||
"/vendor/directFulfillment/inventory/v1/warehouses/{$warehouseId}/items",
|
||||
[
|
||||
'json' => [
|
||||
'inventory' => [
|
||||
'sellingParty' => [
|
||||
'partyId' => $sellingPartyId
|
||||
],
|
||||
'items' => $items,
|
||||
'isFullUpdate' => $isFullUpdate
|
||||
]
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
// The response data is wrapped in a `payload` key
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload'];
|
||||
|
||||
return (new Transaction('inventory_update'))->setExternalId($payload['transactionId']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Service;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Invoice;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Transaction;
|
||||
|
||||
class InvoiceService
|
||||
{
|
||||
/** @var ClientInterface */
|
||||
private $client;
|
||||
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
public function submitInvoice(Invoice $invoice): Transaction
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'POST',
|
||||
'/vendor/directFulfillment/payments/v1/invoices',
|
||||
['json' => [$invoice->toArray()]]
|
||||
);
|
||||
|
||||
// The response data is wrapped in a `payload` key
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload'];
|
||||
|
||||
return (new Transaction('invoice'))->setExternalId($payload['transactionId']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Service;
|
||||
|
||||
use DateTime;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Exception\TransferException as GuzzleTransferException;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\PurchaseOrder;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\PurchaseOrderAcknowledgement;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Transaction;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\TransferException;
|
||||
|
||||
class PurchaseOrderService
|
||||
{
|
||||
/** @var ClientInterface */
|
||||
private $client;
|
||||
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime|null $createdAfter
|
||||
* @param DateTime|null $createdBefore
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return array|string[]
|
||||
*/
|
||||
public function getPurchaseOrderNumbers(
|
||||
?DateTime $createdAfter = null,
|
||||
?DateTime $createdBefore = null,
|
||||
?int $limit = null
|
||||
): array {
|
||||
$orders = $this->getOrders($createdAfter, $createdBefore, $limit);
|
||||
|
||||
return array_map(
|
||||
function (array $order) {
|
||||
return $order['purchaseOrderNumber'];
|
||||
},
|
||||
$orders
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime|null $createdAfter
|
||||
* @param DateTime|null $createdBefore
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return array|PurchaseOrder[]
|
||||
*/
|
||||
public function getPurchaseOrders(
|
||||
?DateTime $createdAfter = null,
|
||||
?DateTime $createdBefore = null,
|
||||
?int $limit = null
|
||||
): array {
|
||||
$orders = $this->getOrders($createdAfter, $createdBefore, $limit);
|
||||
|
||||
return array_map(
|
||||
function (array $order) {
|
||||
return PurchaseOrder::fromPurchaseOrderResponse($order);
|
||||
},
|
||||
$orders
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param DateTime|null $createdAfter
|
||||
* @param DateTime|null $createdBefore
|
||||
* @param int|null $limit
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getOrders(
|
||||
?DateTime $createdAfter = null,
|
||||
?DateTime $createdBefore = null,
|
||||
?int $limit = null
|
||||
): array {
|
||||
$finished = false;
|
||||
$nextToken = null;
|
||||
$orders = [];
|
||||
if ($limit !== null) {
|
||||
$response = $this->sendGetOrdersRequest($createdAfter, $createdBefore, null, $limit);
|
||||
$orders = array_merge($orders, $response['payload']['orders']);
|
||||
} else {
|
||||
while (!$finished) {
|
||||
$response = $this->sendGetOrdersRequest($createdAfter, $createdBefore, $nextToken);
|
||||
if ($response['payload']['pagination']['nextToken']) {
|
||||
$nextToken = $response['payload']['pagination']['nextToken'];
|
||||
} else {
|
||||
$finished = true;
|
||||
}
|
||||
$orders = array_merge($orders, $response['payload']['orders']);
|
||||
}
|
||||
}
|
||||
|
||||
return $orders;
|
||||
}
|
||||
|
||||
public function getOrder(string $purchaseOrderNumber): PurchaseOrder
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
"/vendor/directFulfillment/orders/v1/purchaseOrders/{$purchaseOrderNumber}"
|
||||
);
|
||||
|
||||
$payload = json_decode($response->getBody()->getContents(), true);
|
||||
|
||||
return PurchaseOrder::fromPurchaseOrderResponse($payload);
|
||||
}
|
||||
|
||||
public function submitAcknowledgement(PurchaseOrderAcknowledgement $acknowledgement): Transaction
|
||||
{
|
||||
try {
|
||||
$response = $this->client->request(
|
||||
'POST',
|
||||
'/vendor/directFulfillment/orders/v1/acknowledgements',
|
||||
[
|
||||
'json' => [
|
||||
'orderAcknowledgements' => [$acknowledgement->toArray()],
|
||||
],
|
||||
]
|
||||
);
|
||||
}catch (GuzzleTransferException $exception){
|
||||
throw new TransferException('Error while submitting acknowledgement',0, $exception);
|
||||
}
|
||||
|
||||
// The response data is wrapped in a `payload` key
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload'];
|
||||
|
||||
return (new Transaction('purchase_order_acknowledgement'))->setExternalId($payload['transactionId']);
|
||||
}
|
||||
|
||||
protected function formatDate(DateTime $date)
|
||||
{
|
||||
return $date->format(DateTime::ISO8601);
|
||||
}
|
||||
|
||||
protected function sendGetOrdersRequest(
|
||||
?DateTime $createdAfter,
|
||||
?DateTime $createdBefore,
|
||||
?string $nextToken = null,
|
||||
?int $limit = null
|
||||
): array {
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
'/vendor/directFulfillment/orders/v1/purchaseOrders',
|
||||
[
|
||||
'query' => array_merge(
|
||||
[
|
||||
'createdAfter' => $this->formatDate($createdAfter ?? new DateTime('-7 days')),
|
||||
'createdBefore' => $this->formatDate($createdBefore ?? new DateTime()),
|
||||
'limit' => $limit ?: 100,
|
||||
'includeDetails' => true,
|
||||
'sortOrder' => 'DESC',
|
||||
],
|
||||
$nextToken !== null ? ['nextToken' => $nextToken] : []
|
||||
),
|
||||
]
|
||||
);
|
||||
|
||||
return json_decode($response->getBody()->getContents(), true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Service;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\ShipmentConfirmation;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\ShippingLabel;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\ShippingLabelRequest;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Transaction;
|
||||
|
||||
class ShippingService
|
||||
{
|
||||
/** @var ClientInterface */
|
||||
private $client;
|
||||
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $purchaseOrderNumber
|
||||
*
|
||||
* @throws \GuzzleHttp\Exception\GuzzleException
|
||||
* @return array|ShippingLabel[]
|
||||
*/
|
||||
public function getShippingLabels(string $purchaseOrderNumber): array
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
"/vendor/directFulfillment/shipping/v1/shippingLabels/{$purchaseOrderNumber}"
|
||||
);
|
||||
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload'];
|
||||
|
||||
return array_map(
|
||||
function (array $data) use ($payload) {
|
||||
$label = new ShippingLabel($payload['purchaseOrderNumber'], $data['content'], $payload['labelFormat']);
|
||||
if (isset($data['trackingNumber']) && $data['trackingNumber'] !== '') {
|
||||
$label->setTrackingNumber($data['trackingNumber']);
|
||||
}
|
||||
|
||||
return $label;
|
||||
},
|
||||
$payload['labelData']
|
||||
);
|
||||
}
|
||||
|
||||
public function submitShippingLabelRequest(ShippingLabelRequest $shippingLabelRequest): Transaction
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'POST',
|
||||
'/vendor/directFulfillment/shipping/v1/shippingLabels',
|
||||
[
|
||||
'json' => [
|
||||
'shippingLabelRequests' => [$shippingLabelRequest->toArray()],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
// The response data is wrapped in a `payload` key
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload'];
|
||||
|
||||
return (new Transaction('shipping_label_request'))->setExternalId($payload['transactionId']);
|
||||
}
|
||||
|
||||
public function submitShipmentConfirmation(ShipmentConfirmation $confirmation)
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'POST',
|
||||
'/vendor/directFulfillment/shipping/v1/shipmentConfirmations',
|
||||
[
|
||||
'json' => [
|
||||
'shipmentConfirmations' => [
|
||||
$confirmation->toArray(),
|
||||
],
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
// The response data is wrapped in a `payload` key
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload'];
|
||||
|
||||
return (new Transaction('shipment_confirmation'))->setExternalId($payload['transactionId']);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Service;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Token;
|
||||
use Xentral\Modules\AmazonVendorDF\Exception\IssueTokenException;
|
||||
|
||||
class TokenService
|
||||
{
|
||||
/** @var ClientInterface */
|
||||
private $client;
|
||||
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
public function requestToken(string $refreshToken, string $clientId, string $clientSecret)
|
||||
{
|
||||
try {
|
||||
$response = $this->client->request(
|
||||
'POST',
|
||||
'https://api.amazon.com/auth/o2/token',
|
||||
[
|
||||
'form_params' => [
|
||||
'grant_type' => 'refresh_token',
|
||||
'refresh_token' => $refreshToken,
|
||||
'client_id' => $clientId,
|
||||
'client_secret' => $clientSecret,
|
||||
],
|
||||
]
|
||||
);
|
||||
}catch (BadResponseException $badResponseException){
|
||||
throw IssueTokenException::fromResponse($badResponseException->getResponse());
|
||||
}
|
||||
|
||||
return Token::fromResponse($response);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF\Service;
|
||||
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Transaction;
|
||||
|
||||
class TransactionService
|
||||
{
|
||||
/** @var ClientInterface */
|
||||
private $client;
|
||||
|
||||
public function __construct(ClientInterface $client)
|
||||
{
|
||||
$this->client = $client;
|
||||
}
|
||||
|
||||
public function updateTransactionStatus(Transaction $transaction): Transaction
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
"/vendor/directFulfillment/transactions/v1/transactions/{$transaction->getExternalId()}"
|
||||
);
|
||||
|
||||
// The response data is wrapped in a `payload` key
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload']['transactionStatus'];
|
||||
|
||||
$transaction->setStatus($payload['status']);
|
||||
if($transaction->hasFailed()){
|
||||
$transaction->setErrors($payload['errors']);
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
|
||||
public function getTransactionByTransactionId(string $transactionId): Transaction
|
||||
{
|
||||
$response = $this->client->request(
|
||||
'GET',
|
||||
"/vendor/directFulfillment/transactions/v1/transactions/{$transactionId}"
|
||||
);
|
||||
|
||||
// The response data is wrapped in a `payload` key
|
||||
$payload = json_decode($response->getBody()->getContents(), true)['payload']['transactionStatus'];
|
||||
|
||||
$transaction = new Transaction();
|
||||
$transaction->setStatus($payload['status']);
|
||||
if ($transaction->hasFailed()) {
|
||||
$transaction->setErrors($payload['errors']);
|
||||
}
|
||||
|
||||
return $transaction;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
namespace Xentral\Modules\AmazonVendorDF;
|
||||
|
||||
use Aws\Credentials\Credentials;
|
||||
use Aws\Signature\SignatureV4;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\ClientInterface;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
use Xentral\Modules\AmazonVendorDF\Data\Token;
|
||||
use Xentral\Modules\AmazonVendorDF\Service\InventoryService;
|
||||
use Xentral\Modules\AmazonVendorDF\Service\InvoiceService;
|
||||
use Xentral\Modules\AmazonVendorDF\Service\PurchaseOrderService;
|
||||
use Xentral\Modules\AmazonVendorDF\Service\ShippingService;
|
||||
use Xentral\Modules\AmazonVendorDF\Service\TokenService;
|
||||
use Xentral\Modules\AmazonVendorDF\Service\TransactionService;
|
||||
|
||||
class ServiceFactory
|
||||
{
|
||||
const API_BASE_URL = 'https://sellingpartnerapi-eu.amazon.com';
|
||||
|
||||
/** @var TokenService */
|
||||
private $tokenService;
|
||||
/** @var Token */
|
||||
private $token;
|
||||
/** @var string */
|
||||
private $refreshToken;
|
||||
/** @var string */
|
||||
private $clientId;
|
||||
/** @var string */
|
||||
private $clientSecret;
|
||||
/** @var SignatureV4 */
|
||||
private $signature;
|
||||
/** @var Credentials */
|
||||
private $credentials;
|
||||
/** @var ClientInterface */
|
||||
private $authenticatedClient;
|
||||
/** @var LoggerInterface */
|
||||
private $logger;
|
||||
|
||||
public function __construct(
|
||||
string $refreshToken,
|
||||
string $clientId,
|
||||
string $clientSecret,
|
||||
string $awsIamKey,
|
||||
string $awsIamSecret,
|
||||
LoggerInterface $logger
|
||||
) {
|
||||
$this->tokenService = new TokenService(new Client());
|
||||
$this->refreshToken = $refreshToken;
|
||||
$this->clientId = $clientId;
|
||||
$this->clientSecret = $clientSecret;
|
||||
$this->signature = new SignatureV4('execute-api', 'eu-west-1');
|
||||
$this->credentials = new Credentials($awsIamKey, $awsIamSecret);
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
public function getShippingService(): ShippingService
|
||||
{
|
||||
return new ShippingService($this->getAuthenticatedClient());
|
||||
}
|
||||
|
||||
public function getInvoiceService(): InvoiceService
|
||||
{
|
||||
return new InvoiceService($this->getAuthenticatedClient());
|
||||
}
|
||||
|
||||
public function getInventoryService(): InventoryService
|
||||
{
|
||||
return new InventoryService($this->getAuthenticatedClient());
|
||||
}
|
||||
|
||||
public function getPurchaseOrderService(): PurchaseOrderService
|
||||
{
|
||||
return new PurchaseOrderService($this->getAuthenticatedClient());
|
||||
}
|
||||
|
||||
public function getTransactionService(): TransactionService
|
||||
{
|
||||
return new TransactionService($this->getAuthenticatedClient());
|
||||
}
|
||||
|
||||
private function getAuthenticatedClient(): ClientInterface
|
||||
{
|
||||
if (!$this->authenticatedClient || $this->getToken()->isExpired()) {
|
||||
$stack = HandlerStack::create();
|
||||
$stack->push($this->getSignatureMiddleware());
|
||||
$stack->push($this->getLoggingMiddleWare());
|
||||
|
||||
$this->authenticatedClient = new Client(
|
||||
[
|
||||
'handler' => $stack,
|
||||
'base_uri' => self::API_BASE_URL,
|
||||
'headers' => [
|
||||
'x-amz-access-token' => $this->getToken()->getAccessToken(),
|
||||
],
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
return $this->authenticatedClient;
|
||||
}
|
||||
|
||||
private function getSignatureMiddleware()
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return function (RequestInterface $request, array $options) use ($handler) {
|
||||
return $handler($this->signature->signRequest($request, $this->credentials), $options);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private function getLoggingMiddleWare()
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return function (RequestInterface $request, array $options) use ($handler) {
|
||||
$promise = $handler($request, $options);
|
||||
|
||||
return $promise->then(
|
||||
function (ResponseInterface $response) use ($request) {
|
||||
$this->logRequestAndResponse($request, $response, LogLevel::DEBUG);
|
||||
|
||||
return $response;
|
||||
},
|
||||
function (ResponseInterface $response) use ($request) {
|
||||
$this->logRequestAndResponse($request, $response, LogLevel::ERROR);
|
||||
|
||||
return $response;
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
private function logRequestAndResponse(RequestInterface $request, ResponseInterface $response, string $level)
|
||||
{
|
||||
$request->getBody()->rewind();
|
||||
|
||||
$this->logger->log(
|
||||
$level,
|
||||
'Amazon Vendor DF API request',
|
||||
[
|
||||
'request' => [
|
||||
'uri' => (string)$request->getUri(),
|
||||
'method' => $request->getMethod(),
|
||||
'body' => json_decode($request->getBody()->getContents(), true),
|
||||
],
|
||||
'response' => [
|
||||
'status_code' => $response->getStatusCode(),
|
||||
'headers' => $response->getHeaders(),
|
||||
'body' => json_decode($response->getBody()->getContents(), true),
|
||||
],
|
||||
]
|
||||
|
||||
);
|
||||
|
||||
$response->getBody()->rewind();
|
||||
}
|
||||
|
||||
private function getToken()
|
||||
{
|
||||
if (!$this->token) {
|
||||
$this->token = $this->tokenService->requestToken($this->refreshToken, $this->clientId, $this->clientSecret);
|
||||
}
|
||||
|
||||
return $this->token;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user