From ce21cccdfbf393bde925f09baab59cc5ef39a4e1 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 22:24:43 +0200 Subject: [PATCH 1/8] Add files via upload --- src/ApiConnectors/InvoiceApiConnector.php | 76 ++++++++++++++++++++--- 1 file changed, 68 insertions(+), 8 deletions(-) diff --git a/src/ApiConnectors/InvoiceApiConnector.php b/src/ApiConnectors/InvoiceApiConnector.php index 3c9a6219..84678963 100644 --- a/src/ApiConnectors/InvoiceApiConnector.php +++ b/src/ApiConnectors/InvoiceApiConnector.php @@ -2,6 +2,7 @@ namespace PhpTwinfield\ApiConnectors; +use PhpTwinfield\Customer; use PhpTwinfield\DomDocuments\InvoicesDocument; use PhpTwinfield\Exception; use PhpTwinfield\Invoice; @@ -10,6 +11,7 @@ use PhpTwinfield\Request as Request; use PhpTwinfield\Response\MappedResponseCollection; use PhpTwinfield\Response\Response; +use PhpTwinfield\Services\FinderService; use Webmozart\Assert\Assert; /** @@ -25,7 +27,7 @@ class InvoiceApiConnector extends BaseApiConnector { /** - * Requires a specific invoice based off the passed in code, invoiceNumber and optionally the office. + * Requires a specific Invoice based off the passed in code, invoiceNumber and optionally the office. * * @param string $code * @param string $invoiceNumber @@ -35,7 +37,7 @@ class InvoiceApiConnector extends BaseApiConnector */ public function get(string $code, string $invoiceNumber, Office $office) { - // Make a request to read a single invoice. Set the required values + // Make a request to read a single Invoice. Set the required values $request_invoice = new Request\Read\Invoice(); $request_invoice ->setCode($code) @@ -57,12 +59,8 @@ public function get(string $code, string $invoiceNumber, Office $office) */ public function send(Invoice $invoice): Invoice { - $invoiceResponses = $this->sendAll([$invoice]); - - Assert::count($invoiceResponses, 1); - - foreach ($invoiceResponses as $invoiceResponse) { - return $invoiceResponse->unwrap(); + foreach($this->sendAll([$invoice]) as $each) { + return $each->unwrap(); } } @@ -93,4 +91,66 @@ public function sendAll(array $invoices): MappedResponseCollection return InvoiceMapper::map($response); }); } + + /** + * List all sales invoices. + * + * @param string $pattern The search pattern. May contain wildcards * and ? + * @param int $field The search field determines which field or fields will be searched. The available fields + * depends on the finder type. Passing a value outside the specified values will cause an + * error. + * @param int $firstRow First row to return, useful for paging + * @param int $maxRows Maximum number of rows to return, useful for paging + * @param array $options The Finder options. Passing an unsupported name or value causes an error. It's possible + * to add multiple options. An option name may be used once, specifying an option multiple + * times will cause an error. + * + * @return Invoice[] The sales invoices found. + */ + public function listAll( + string $pattern = '*', + int $field = 0, + int $firstRow = 1, + int $maxRows = 100, + array $options = [] + ): array { + $optionsArrayOfString = array('ArrayOfString' => array()); + + foreach ($options as $key => $value) { + $optionsArrayOfString['ArrayOfString'][] = array($key, $value); + } + + $response = $this->getFinderService()->searchFinder(FinderService::TYPE_LIST_OF_AVAILABLE_INVOICES, $pattern, $field, $firstRow, $maxRows, $optionsArrayOfString); + + if ($response->data->TotalRows == 0) { + return []; + } + + $invoices = []; + + foreach ($response->data->Items->ArrayOfString as $invoiceArray) { + $invoice = new Invoice(); + $customer = new Customer(); + + if (isset($invoiceArray->string[0])) { + $invoice->setInvoiceNumber($invoiceArray->string[0]); + $invoice->setInvoiceAmount($invoiceArray->string[1]); + $customer->setCode($invoiceArray->string[2]); + $invoice->setCustomerName($invoiceArray->string[3]); + $invoice->setDebitCredit($invoiceArray->string[4]); + } else { + $invoice->setInvoiceNumber($invoiceArray[0]); + $invoice->setInvoiceAmount($invoiceArray[1]); + $customer->setCode($invoiceArray[2]); + $invoice->setCustomerName($invoiceArray[3]); + $invoice->setDebitCredit($invoiceArray[4]); + } + + $invoice->setCustomer($customer); + + $invoices[] = $invoice; + } + + return $invoices; + } } From 4ca9fa87a8e99e148b659f4d66007bf2065b0c34 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 22:24:54 +0200 Subject: [PATCH 2/8] Add files via upload --- src/DomDocuments/InvoicesDocument.php | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/DomDocuments/InvoicesDocument.php b/src/DomDocuments/InvoicesDocument.php index ad6a9274..808866d9 100644 --- a/src/DomDocuments/InvoicesDocument.php +++ b/src/DomDocuments/InvoicesDocument.php @@ -24,10 +24,10 @@ final protected function getRootTagName(): string /** * Turns a passed Invoice class into the required markup for interacting * with Twinfield. - * + * * This method doesn't return anything, instead just adds the invoice * to this DOMDocument instance for submission usage. - * + * * @access public * @param Invoice $invoice * @return void | [Adds to this instance] @@ -40,7 +40,7 @@ public function addInvoice(Invoice $invoice) // Makes a child header element $headerElement = $this->createElement('header'); $invoiceElement->appendChild($headerElement); - + // Set customer element $customer = $invoice->getCustomer(); @@ -66,20 +66,20 @@ public function addInvoice(Invoice $invoice) 'headertext' => 'getHeaderText', 'footertext' => 'getFooterText' ); - + // Go through each element and use the assigned method foreach ($headerTags as $tag => $method) { $value = $this->getValueFromCallback([$invoice, $method]); - + if(null !== $value) { // Make text node for method value $node = $this->createTextNode($value); - + // Make the actual element and assign the node $element = $this->createElement($tag); $element->appendChild($node); - + // Add the full element $headerElement->appendChild($element); } @@ -88,7 +88,7 @@ public function addInvoice(Invoice $invoice) // Add orders $linesElement = $this->createElement('lines'); $invoiceElement->appendChild($linesElement); - + // Elements and their associated methods for lines $lineTags = array( 'quantity' => 'getQuantity', @@ -96,6 +96,7 @@ public function addInvoice(Invoice $invoice) 'subarticle' => 'getSubArticle', 'description' => 'getDescription', 'unitspriceexcl' => 'getUnitsPriceExcl', + 'unitspriceinc' => 'getUnitsPriceInc', 'units' => 'getUnits', 'vatcode' => 'getVatCode', 'freetext1' => 'getFreeText1', @@ -116,7 +117,7 @@ public function addInvoice(Invoice $invoice) // Go through each element and use the assigned method foreach ($lineTags as $tag => $method) { - + // Make text node for method value $node = $this->createTextNode($this->getValueFromCallback([$line, $method])); From be6a400ae631d22396727af22a07792ee9f3471d Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 22:25:10 +0200 Subject: [PATCH 3/8] Add files via upload --- src/Mappers/InvoiceMapper.php | 168 +++++++++++++++++++++------------- 1 file changed, 106 insertions(+), 62 deletions(-) diff --git a/src/Mappers/InvoiceMapper.php b/src/Mappers/InvoiceMapper.php index 5fccf1f9..f1449391 100644 --- a/src/Mappers/InvoiceMapper.php +++ b/src/Mappers/InvoiceMapper.php @@ -4,6 +4,7 @@ use PhpTwinfield\Customer; use PhpTwinfield\Invoice; use PhpTwinfield\InvoiceLine; +use PhpTwinfield\InvoiceVatLine; use PhpTwinfield\InvoiceTotals; use PhpTwinfield\Response\Response; @@ -12,44 +13,40 @@ class InvoiceMapper extends BaseMapper public static function map(Response $response) { $responseDOM = $response->getResponseDocument(); + $invoiceElement = $responseDOM->documentElement; + + // Generate new Invoice + $invoice = new Invoice(); + $invoice->setResult($invoiceElement->getAttribute('result')); $invoiceTags = array( - 'office' => 'setOffice', - 'invoicetype' => 'setInvoiceType', - 'invoicenumber' => 'setInvoiceNumber', - 'status' => 'setStatus', - 'currency' => 'setCurrency', - 'period' => 'setPeriod', - 'invoicedate' => 'setInvoiceDate', - 'duedate' => 'setDueDateFromString', - 'performancedate' => 'setPerformanceDate', - 'paymentmethod' => 'setPaymentMethod', 'bank' => 'setBank', - 'invoiceaddressnumber' => 'setInvoiceAddressNumber', + 'currency' => 'setCurrency', 'deliveraddressnumber' => 'setDeliverAddressNumber', - 'headertext' => 'setHeaderText', + 'duedate' => 'setDueDate', 'footertext' => 'setFooterText', + 'headertext' => 'setHeaderText', + 'invoiceaddressnumber' => 'setInvoiceAddressNumber', + 'invoicedate' => 'setInvoiceDate', + 'invoicenumber' => 'setInvoiceNumber', + 'invoicetype' => 'setInvoiceType', + 'office' => 'setOffice', + 'paymentmethod' => 'setPaymentMethod', + 'performancedate' => 'setPerformanceDate', + 'period' => 'setPeriod', + 'status' => 'setStatus', ); - $customerTags = array( - 'customer' => 'setCode', - ); - - $totalsTags = array( - 'valueexcl' => 'setValueExcl', - 'valueinc' => 'setValueInc', - ); - - // Generate new Invoice - $invoice = new Invoice(); - // Loop through all invoice tags foreach ($invoiceTags as $tag => $method) { - self::setFromTagValue($responseDOM, $tag, [$invoice, $method]); } - // Make a custom, and loop through custom tags + // Make a customer, and loop through custom tags + $customerTags = array( + 'customer' => 'setCode', + ); + $customer = new Customer(); foreach ($customerTags as $tag => $method) { $_tag = $responseDOM->getElementsByTagName($tag)->item(0); @@ -59,56 +56,103 @@ public static function map(Response $response) } } + // Set the custom class to the invoice + $invoice->setCustomer($customer); + // Make an InvoiceTotals and loop through custom tags + $totalsTags = array( + 'valueexcl' => 'setValueExcl', + 'valueinc' => 'setValueInc', + ); + $invoiceTotals = new InvoiceTotals(); - foreach ($totalsTags as $tag => $method) { - $_tag = $responseDOM->getElementsByTagName($tag)->item(0); - if (isset($_tag) && isset($_tag->textContent)) { - $invoiceTotals->$method($_tag->textContent); + $totalElement = $responseDOM->getElementsByTagName('totals')->item(0); + + if ($totalElement !== null) { + // Go through each total element and add to the assigned method + foreach ($totalsTags as $tag => $method) { + $invoiceTotals->$method(self::getField($totalElement, $tag)); } } - // Set the custom classes to the invoice - $invoice->setCustomer($customer); + // Set the custom class to the invoice $invoice->setTotals($invoiceTotals); - $lineTags = array( - 'article' => 'setArticle', - 'subarticle' => 'setSubArticle', - 'quantity' => 'setQuantity', - 'units' => 'setUnits', - 'allowdiscountorpremium' => 'setAllowDiscountOrPremium', - 'description' => 'setDescription', - 'valueexcl' => 'setValueExcl', - 'vatvalue' => 'setVatValue', - 'valueinc' => 'setValueInc', - 'unitspriceexcl' => 'setUnitsPriceExcl', - 'unitspriceinc' => 'setUnitsPriceInc', - 'freetext1' => 'setFreeText1', - 'freetext2' => 'setFreeText2', - 'freetext3' => 'setFreeText3', - 'performancedate' => 'setPerformanceDate', - 'performancetype' => 'setPerformanceType', - 'dim1' => 'setDim1', - ); + $linesDOMTag = $responseDOM->getElementsByTagName('lines'); + + if (isset($linesDOMTag) && $linesDOMTag->length > 0) { + // Element tags and their methods for lines + $lineTags = array( + 'allowdiscountorpremium' => 'setAllowDiscountOrPremium', + 'article' => 'setArticle', + 'description' => 'setDescription', + 'dim1' => 'setDim1', + 'freetext1' => 'setFreeText1', + 'freetext2' => 'setFreeText2', + 'freetext3' => 'setFreeText3', + 'performancedate' => 'setPerformanceDate', + 'performancetype' => 'setPerformanceType', + 'quantity' => 'setQuantity', + 'subarticle' => 'setSubArticle', + 'units' => 'setUnits', + 'unitspriceexcl' => 'setUnitsPriceExcl', + 'unitspriceinc' => 'setUnitsPriceInc', + 'valueexcl' => 'setValueExcl', + 'valueinc' => 'setValueInc', + 'vatcode' => 'setVatCode', + 'vatvalue' => 'setVatValue', + ); + + $linesDOM = $linesDOMTag->item(0); + + // Loop through each returned lines for the invoice + foreach ($linesDOM->childNodes as $lineDOM) { + + $invoiceLine = new InvoiceLine(); + $invoiceLine->setID($lineDOM->getAttribute('id')); + + foreach ($lineTags as $tag => $method) { + + $content = self::getField($lineDOM, $tag); + + if (null !== $content) { + $invoiceLine->$method($content); + } + } - /** @var \DOMElement $lineDOM */ - foreach ($responseDOM->getElementsByTagName('line') as $lineDOM) { + $invoice->addLine($invoiceLine); + } + } + + $vatlinesDOMTag = $responseDOM->getElementsByTagName('vatlines'); + + if (isset($vatlinesDOMTag) && $vatlinesDOMTag->length > 0) { + // Element tags and their methods for vatlines + $vatlineTags = array( + 'performancedate' => 'setPerformanceDate', + 'performancetype' => 'setPerformanceType', + 'vatcode' => 'setVatCode', + 'vatvalue' => 'setVatValue', + ); - $invoiceLine = new InvoiceLine(); - $invoiceLine->setID($lineDOM->getAttribute('id')); + $vatlinesDOM = $vatlinesDOMTag->item(0); - foreach ($lineTags as $tag => $method) { + // Loop through each returned lines for the invoice + foreach ($vatlinesDOM->childNodes as $vatlineDOM) { + $invoiceVatLine = new InvoiceVatLine(); - $content = self::getField($lineDOM, $tag); + foreach ($vatlineTags as $tag => $method) { - if (null !== $content) { - $invoiceLine->$method($content); + $content = self::getField($vatlineDOM, $tag); + + if (null !== $content) { + $invoiceVatLine->$method($content); + } } - } - $invoice->addLine($invoiceLine); + $invoice->addVatLine($invoiceVatLine); + } } // Financial elements and their methods @@ -130,4 +174,4 @@ public static function map(Response $response) return $invoice; } -} +} \ No newline at end of file From 5c353ee71b06c94dbe717e8a43b77baedda56505 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 22:25:24 +0200 Subject: [PATCH 4/8] Add files via upload --- src/Request/Read/Invoice.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Request/Read/Invoice.php b/src/Request/Read/Invoice.php index 27aec93a..8dd88bf8 100644 --- a/src/Request/Read/Invoice.php +++ b/src/Request/Read/Invoice.php @@ -2,7 +2,7 @@ namespace PhpTwinfield\Request\Read; /** - * Used to request a specific invoice from a certain + * Used to request a specific Invoice from a certain * code, number and office. * * @package PhpTwinfield From 561ed09cd536d2f79305b133542682a5074d8d44 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 22:25:37 +0200 Subject: [PATCH 5/8] Add files via upload --- src/Invoice.php | 71 ++++++++++++++++++++++++++++++++++++++++-- src/InvoiceVatLine.php | 55 ++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 src/InvoiceVatLine.php diff --git a/src/Invoice.php b/src/Invoice.php index 658ed7b4..d5bf3b89 100644 --- a/src/Invoice.php +++ b/src/Invoice.php @@ -24,20 +24,22 @@ * * @see https://c3.twinfield.com/webservices/documentation/#/ApiReference/SalesInvoices * @todo Add documentation and typehints to all properties. - * @todo Add support for VatLines. */ -class Invoice +class Invoice extends BaseObject { use PeriodField; - use DueDateField; use OfficeField; private $customer; + private $customerName; + private $debitCredit; + private $invoiceAmount; private $invoiceType; private $invoiceNumber; private $status; private $currency; private $invoiceDate; + private $dueDate; private $performanceDate; private $paymentMethod; private $bank; @@ -69,6 +71,25 @@ public function getLines(): array return $this->lines; } + /** + * @var InvoiceVatLine[] + */ + private $vatlines = []; + + public function addVatLine(InvoiceVatLine $vatline) + { + $this->vatlines[] = $vatline; + return $this; + } + + /** + * @return InvoiceVatLine[] + */ + public function getVatLines(): array + { + return $this->vatlines; + } + public function getCustomer(): Customer { return $this->customer; @@ -80,6 +101,28 @@ public function setCustomer(Customer $customer) return $this; } + public function getCustomerName() + { + return $this->customerName; + } + + public function setCustomerName($customerName) + { + $this->customerName = $customerName; + return $this; + } + + public function getDebitCredit() + { + return $this->debitCredit; + } + + public function setDebitCredit($debitCredit) + { + $this->debitCredit = $debitCredit; + return $this; + } + public function setTotals(InvoiceTotals $totals) { $this->totals = $totals; @@ -91,6 +134,17 @@ public function getTotals(): InvoiceTotals return $this->totals; } + public function getInvoiceAmount() + { + return $this->invoiceAmount; + } + + public function setInvoiceAmount($invoiceAmount) + { + $this->invoiceAmount = $invoiceAmount; + return $this; + } + public function getInvoiceType() { return $this->invoiceType; @@ -146,6 +200,17 @@ public function setInvoiceDate($invoiceDate) return $this; } + public function getDueDate() + { + return $this->dueDate; + } + + public function setDueDate($dueDate) + { + $this->dueDate = $dueDate; + return $this; + } + public function getPerformanceDate() { return $this->performanceDate; diff --git a/src/InvoiceVatLine.php b/src/InvoiceVatLine.php new file mode 100644 index 00000000..50ba73a8 --- /dev/null +++ b/src/InvoiceVatLine.php @@ -0,0 +1,55 @@ +vatValue; + } + + public function setVatValue($vatValue) + { + $this->vatValue = $vatValue; + return $this; + } + + public function getPerformanceDate() + { + return $this->performanceDate; + } + + public function setPerformanceDate($performanceDate) + { + $this->performanceDate = $performanceDate; + return $this; + } + + public function getPerformanceType(): ?PerformanceType + { + return $this->performanceType; + } + + public function setPerformanceType(?PerformanceType $performanceType): self + { + $this->performanceType = $performanceType; + return $this; + } +} From 0c171da00019d1953008155510fca2ccbcc94d90 Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 22:26:57 +0200 Subject: [PATCH 6/8] Update InvoicesDocument.php --- src/DomDocuments/InvoicesDocument.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/DomDocuments/InvoicesDocument.php b/src/DomDocuments/InvoicesDocument.php index 808866d9..20d8e438 100644 --- a/src/DomDocuments/InvoicesDocument.php +++ b/src/DomDocuments/InvoicesDocument.php @@ -96,7 +96,7 @@ public function addInvoice(Invoice $invoice) 'subarticle' => 'getSubArticle', 'description' => 'getDescription', 'unitspriceexcl' => 'getUnitsPriceExcl', - 'unitspriceinc' => 'getUnitsPriceInc', + 'unitspriceinc' => 'getUnitsPriceInc', 'units' => 'getUnits', 'vatcode' => 'getVatCode', 'freetext1' => 'getFreeText1', From 57b2c31cf9a44441fdb953b2192c3370e735cd3a Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 23:41:49 +0200 Subject: [PATCH 7/8] Update InvoiceMapper.php --- src/Mappers/InvoiceMapper.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Mappers/InvoiceMapper.php b/src/Mappers/InvoiceMapper.php index f1449391..4d5ab62a 100644 --- a/src/Mappers/InvoiceMapper.php +++ b/src/Mappers/InvoiceMapper.php @@ -108,7 +108,10 @@ public static function map(Response $response) // Loop through each returned lines for the invoice foreach ($linesDOM->childNodes as $lineDOM) { - + if( $lineDOM->nodeType !== 1 ) { + continue; + } + $invoiceLine = new InvoiceLine(); $invoiceLine->setID($lineDOM->getAttribute('id')); @@ -140,6 +143,10 @@ public static function map(Response $response) // Loop through each returned lines for the invoice foreach ($vatlinesDOM->childNodes as $vatlineDOM) { + if( $vatlineDOM->nodeType !== 1 ) { + continue; + } + $invoiceVatLine = new InvoiceVatLine(); foreach ($vatlineTags as $tag => $method) { @@ -174,4 +181,4 @@ public static function map(Response $response) return $invoice; } -} \ No newline at end of file +} From 6b42898efb3844032b17cb2ef4e05d969964b44a Mon Sep 17 00:00:00 2001 From: iranl Date: Sun, 28 Apr 2019 23:51:11 +0200 Subject: [PATCH 8/8] Add files via upload --- src/Mappers/InvoiceMapper.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Mappers/InvoiceMapper.php b/src/Mappers/InvoiceMapper.php index 4d5ab62a..4d70f536 100644 --- a/src/Mappers/InvoiceMapper.php +++ b/src/Mappers/InvoiceMapper.php @@ -108,10 +108,10 @@ public static function map(Response $response) // Loop through each returned lines for the invoice foreach ($linesDOM->childNodes as $lineDOM) { - if( $lineDOM->nodeType !== 1 ) { + if ($lineDOM->nodeType !== 1) { continue; } - + $invoiceLine = new InvoiceLine(); $invoiceLine->setID($lineDOM->getAttribute('id')); @@ -143,10 +143,10 @@ public static function map(Response $response) // Loop through each returned lines for the invoice foreach ($vatlinesDOM->childNodes as $vatlineDOM) { - if( $vatlineDOM->nodeType !== 1 ) { + if ($vatlineDOM->nodeType !== 1) { continue; } - + $invoiceVatLine = new InvoiceVatLine(); foreach ($vatlineTags as $tag => $method) { @@ -181,4 +181,4 @@ public static function map(Response $response) return $invoice; } -} +} \ No newline at end of file