Initial xentral_oss_20.3.c9ffacf

This commit is contained in:
Alex
2021-05-21 08:49:41 +02:00
parent 5406e4a551
commit 34e5ac43d9
18884 changed files with 2109867 additions and 0 deletions
@@ -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(),
];
}
}