diff --git a/src/Constants/Constraints.php b/src/Constants/Constraints.php index 8c9dd34..ea2a905 100644 --- a/src/Constants/Constraints.php +++ b/src/Constants/Constraints.php @@ -148,14 +148,21 @@ final class Constraints const MAX_LENGTH_ITEM_CODE = 32; /** - * Максимальная длина наименования дополнительного реквизита (1085) + * Максимальная длина значения дополнительного реквизита чека (1192) + * + * @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32 + */ + const MAX_LENGTH_ADD_CHECK_PROP = 16; + + /** + * Максимальная длина наименования дополнительного реквизита пользователя (1085) * * @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32 */ const MAX_LENGTH_ADD_USER_PROP_NAME = 64; /** - * Максимальная длина значения дополнительного реквизита (1086) + * Максимальная длина значения дополнительного реквизита пользователя (1086) * * @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32 */ diff --git a/src/Constants/Ffd105Tags.php b/src/Constants/Ffd105Tags.php index ed6cc5f..1fb0914 100644 --- a/src/Constants/Ffd105Tags.php +++ b/src/Constants/Ffd105Tags.php @@ -227,6 +227,11 @@ final class Ffd105Tags */ const DOC_VAT_TYPE_VAT120 = 1106; + /** + * Значение дополнительного реквизита чека + */ + const DOC_ADD_CHECK_PROP_VALUE = 1192; + /** * Дополнительный реквизит пользователя */ diff --git a/src/Entities/AdditionalUserProps.php b/src/Entities/AdditionalUserProps.php index 0d1739b..bec5123 100644 --- a/src/Entities/AdditionalUserProps.php +++ b/src/Entities/AdditionalUserProps.php @@ -20,7 +20,7 @@ use AtolOnline\Exceptions\{ use JetBrains\PhpStorm\Pure; /** - * Класс, описывающий дополнительный реквизит + * Класс, описывающий дополнительный реквизит пользователя * * @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32 */ diff --git a/src/Entities/Receipt.php b/src/Entities/Receipt.php new file mode 100644 index 0000000..8f1326b --- /dev/null +++ b/src/Entities/Receipt.php @@ -0,0 +1,394 @@ +setClient($client)->setCompany($company)->setItems($items)->setPayments($payments); + } + + /** + * Возвращает установленного покупателя + * + * @return Client + */ + public function getClient(): Client + { + return $this->client; + } + + /** + * Устанаваливает покупателя + * + * @param Client $client + * @return Receipt + */ + public function setClient(Client $client): self + { + $this->client = $client; + return $this; + } + + /** + * Возвращает установленного продавца + * + * @return Company + */ + public function getCompany(): Company + { + return $this->company; + } + + /** + * Устанаваливает продавца + * + * @param Company $company + * @return Receipt + */ + public function setCompany(Company $company): self + { + $this->company = $company; + return $this; + } + + /** + * Возвращает установленного агента + * + * @return AgentInfo + */ + public function getAgentInfo(): ?AgentInfo + { + return $this->agent_info; + } + + /** + * Устанаваливает агента + * + * @param AgentInfo|null $agent_info + * @return Receipt + */ + public function setAgentInfo(?AgentInfo $agent_info): self + { + $this->agent_info = $agent_info; + return $this; + } + + /** + * Поставщика + * + * @return Supplier|null + */ + public function getSupplier(): ?Supplier + { + return $this->supplier; + } + + /** + * Поставщика + * + * @param Supplier|null $supplier + * @return Receipt + */ + public function setSupplier(?Supplier $supplier): self + { + $this->supplier = $supplier; + return $this; + } + + /** + * Возвращает установленную коллекцию предметов расчёта + * + * @return Items + */ + public function getItems(): Items + { + return $this->items; + } + + /** + * Устанаваливает коллекцию предметов расчёта + * + * @todo исключение при пустой коллекции + * @param Items $items + * @return Receipt + */ + public function setItems(Items $items): self + { + $this->items = $items; + return $this; + } + + /** + * Возвращает установленную коллекцию оплат + * + * @return Payments + */ + public function getPayments(): Payments + { + return $this->payments; + } + + /** + * Устанаваливает коллекцию оплат + * + * @todo исключение при пустой коллекции + * @param Payments $payments + * @return Receipt + */ + public function setPayments(Payments $payments): self + { + $this->payments = $payments; + return $this; + } + + /** + * Возвращает установленную коллекцию ставок НДС + * + * @return Vats|null + */ + public function getVats(): ?Vats + { + return $this->vats; + } + + /** + * Устанаваливает коллекцию ставок НДС + * + * @param Vats|null $vats + * @return Receipt + */ + public function setVats(?Vats $vats): self + { + $this->vats = $vats; + return $this; + } + + /** + * Возвращает полную сумму чека + * + * @return float + */ + public function getTotal(): float + { + return $this->total; + } + + /** + * Устанавливает полную сумму чека + * + * @param float $total + * @return Receipt + */ + public function setTotal(float $total): self + { + $this->total = $total; + return $this; + } + + /** + * Возвращает установленного кассира + * + * @return string|null + */ + public function getCashier(): ?string + { + return $this->cashier; + } + + /** + * Устанаваливает кассира + * + * @param string|null $cashier + * @return Receipt + * @throws TooLongCashierException + */ + public function setCashier(?string $cashier): self + { + if (is_string($cashier)) { + $cashier = trim($cashier); + if (mb_strlen($cashier) > Constraints::MAX_LENGTH_CASHIER_NAME) { + throw new TooLongCashierException($cashier); + } + } + $this->cashier = empty($cashier) ? null : $cashier; + return $this; + } + + /** + * Возвращает установленный дополнительный реквизит чека + * + * @return string|null + */ + public function getAddCheckProps(): ?string + { + return $this->add_check_props; + } + + /** + * Устанаваливает дополнительный реквизит чека + * + * @param string|null $add_check_props + * @return Receipt + * @throws TooLongAddCheckPropException + */ + public function setAddCheckProps(?string $add_check_props): self + { + if (is_string($add_check_props)) { + $add_check_props = trim($add_check_props); + if (mb_strlen($add_check_props) > Constraints::MAX_LENGTH_ADD_CHECK_PROP) { + throw new TooLongAddCheckPropException($add_check_props); + } + } + $this->add_check_props = empty($add_check_props) ? null : $add_check_props; + return $this; + } + + /** + * Возвращает установленный дополнительный реквизит пользователя + * + * @return AdditionalUserProps|null + */ + public function getAddUserProps(): ?AdditionalUserProps + { + return $this->add_user_props; + } + + /** + * Устанаваливает дополнительный реквизит пользователя + * + * @param AdditionalUserProps|null $add_user_props + * @return Receipt + */ + public function setAddUserProps(?AdditionalUserProps $add_user_props): self + { + $this->add_user_props = $add_user_props; + return $this; + } + + /** + * Возвращает массив для кодирования в json + * + * @throws Exception + */ + public function jsonSerialize(): array + { + $json = [ + 'client' => $this->getClient(), + 'company' => $this->getCompany(), + 'items' => $this->getItems(), + 'total' => $this->getTotal(), + 'payment' => $this->getPayments(), + ]; + $this->getAgentInfo()?->jsonSerialize() && $json['agent_info'] = $this->getAgentInfo(); + $this->getSupplier()?->jsonSerialize() && $json['vats'] = $this->getVats(); + $this->getVats()?->jsonSerialize() && $json['vats'] = $this->getVats(); + !is_null($this->getAddCheckProps()) && $json['additional_check_props'] = $this->getAddCheckProps(); + !is_null($this->getCashier()) && $json['cashier'] = $this->getCashier(); + $this->getAddUserProps()?->jsonSerialize() && $json['additional_user_props'] = $this->getAddUserProps(); + return $json; + } + + ///** + // * Пересчитывает, сохраняет и возвращает итоговую сумму чека по всем позициям (включая НДС). Тег ФФД - 1020. + // * + // * @return float + // * @throws Exception + // */ + //public function calcTotal(): float + //{ + // $sum = 0; + // $this->clearVats(); + // foreach ($this->items->get() as $item) { + // $sum += $item->calcSum(); + // $this->addVat(new Vat($item->getVat()->getType(), $item->getSum())); + // } + // return $this->total = round($sum, 2); + //} +} diff --git a/src/Entities/todo_Document.php b/src/Entities/todo_Document.php deleted file mode 100644 index f79bde2..0000000 --- a/src/Entities/todo_Document.php +++ /dev/null @@ -1,468 +0,0 @@ -vats = new VatArray(); - $this->payments = new PaymentArray(); - $this->items = new ItemArray(); - } - - /** - * Удаляет все налоги из документа и предметов расчёта - * - * @return $this - * @throws TooManyVatsException Слишком много ставок НДС - */ - public function clearVats(): todoDocument - { - $this->setVats([]); - return $this; - } - - /** - * Добавляет новую ставку НДС в массив ставок НДС - * - * @param Vat $vat Объект ставки НДС - * @return $this - * @throws TooManyVatsException Слишком много ставок НДС - */ - public function addVat(Vat $vat): todoDocument - { - $this->vats->add($vat); - return $this; - } - - /** - * Возвращает массив ставок НДС - * - * @return Vat[] - */ - public function getVats(): array - { - return $this->vats->get(); - } - - /** - * Устанавливает массив ставок НДС - * - * @param Vat[] $vats Массив ставок НДС - * @return $this - * @throws TooManyVatsException Слишком много ставок НДС - * @throws Exception - */ - public function setVats(array $vats): todoDocument - { - $this->vats->set($vats); - return $this; - } - - /** - * Добавляет новую оплату в массив оплат - * - * @param todoPayment $payment Объект оплаты - * @return $this - * @throws Exception - * @throws TooManyPaymentsException Слишком много оплат - */ - public function addPayment(todoPayment $payment): todoDocument - { - if (count($this->getPayments()) == 0 && !$payment->getSum()) { - $payment->setSum($this->calcTotal()); - } - $this->payments->add($payment); - return $this; - } - - /** - * Возвращает массив оплат - * - * @return todoPayment[] - */ - public function getPayments(): array - { - return $this->payments->get(); - } - - /** - * Устанавливает массив оплат - * - * @param todoPayment[] $payments Массив оплат - * @return $this - * @throws TooManyPaymentsException Слишком много оплат - */ - public function setPayments(array $payments): todoDocument - { - $this->payments->set($payments); - return $this; - } - - /** - * Добавляет новый предмет расчёта в массив предметов расчёта - * - * @param Item $item Объект предмета расчёта - * @return $this - * @throws TooManyItemsException Слишком много предметов расчёта - */ - public function addItem(Item $item): todoDocument - { - $this->items->add($item); - return $this; - } - - /** - * Возвращает массив предметов расчёта - * - * @return Item[] - */ - public function getItems(): array - { - return $this->items->get(); - } - - /** - * Устанавливает массив предметов расчёта - * - * @param Item[] $items Массив предметов расчёта - * @return $this - * @throws TooManyItemsException Слишком много предметов расчёта - */ - public function setItems(array $items): todoDocument - { - $this->items->set($items); - return $this; - } - - /** - * Возвращает заданного клиента (покупателя) - * - * @return Client|null - */ - public function getClient(): ?Client - { - return $this->client; - } - - /** - * Устанавливает клиента (покупателя) - * - * @param Client|null $client - * @return $this - */ - public function setClient(?Client $client): todoDocument - { - $this->client = $client; - return $this; - } - - /** - * Возвращает заданную компанию (продавца) - * - * @return Company|null - */ - public function getCompany(): ?Company - { - return $this->company; - } - - /** - * Устанавливает компанию (продавца) - * - * @param Company|null $company - * @return $this - */ - public function setCompany(?Company $company): todoDocument - { - $this->company = $company; - return $this; - } - - /** - * Возвращает ФИО кассира. Тег ФФД - 1021. - * - * @return string|null - */ - public function getCashier(): ?string - { - return $this->cashier; - } - - /** - * Устанавливает ФИО кассира. Тег ФФД - 1021. - * - * @param string|null $cashier - * @return $this - * @throws TooLongCashierException - */ - public function setCashier(?string $cashier): todoDocument - { - if ($cashier !== null) { - $cashier = trim($cashier); - if (mb_strlen($cashier) > Constraints::MAX_LENGTH_CASHIER_NAME) { - throw new TooLongCashierException($cashier, Constraints::MAX_LENGTH_CASHIER_NAME); - } - } - $this->cashier = $cashier; - return $this; - } - - /** - * Возвращает данные коррекции - * - * @return todoCorrectionInfo|null - */ - public function getCorrectionInfo(): ?todoCorrectionInfo - { - return $this->correction_info; - } - - /** - * Устанавливает данные коррекции - * - * @param todoCorrectionInfo|null $correction_info - * @return $this - */ - public function setCorrectionInfo(?todoCorrectionInfo $correction_info): todoDocument - { - $this->correction_info = $correction_info; - return $this; - } - - /** - * Пересчитывает, сохраняет и возвращает итоговую сумму чека по всем позициям (включая НДС). Тег ФФД - 1020. - * - * @return float - * @throws Exception - */ - public function calcTotal(): float - { - $sum = 0; - $this->clearVats(); - foreach ($this->items->get() as $item) { - $sum += $item->calcSum(); - $this->addVat(new Vat($item->getVat()->getType(), $item->getSum())); - } - return $this->total = round($sum, 2); - } - - /** - * Возвращает итоговую сумму чека. Тег ФФД - 1020. - * - * @return float - */ - public function getTotal(): float - { - return $this->total; - } - - /** - * Собирает объект документа из сырой json-строки - * - * @param string $json - * @return todoDocument - * @throws TooLongEmailException - * @throws InvalidEmailException - * @throws AtolException - * @throws InvalidInnLengthException - * @throws InvalidJsonException - * @throws TooLongItemNameException - * @throws TooLongPaymentAddressException - * @throws TooLongClientContactException - * @throws TooHighPriceException - * @throws TooManyException - * @throws TooManyItemsException - * @throws TooManyPaymentsException - * @throws TooLongMeasurementUnitException - * @throws TooLongUserdataException - * @throws Exception - */ - public static function fromRaw(string $json): todoDocument - { - $array = json_decode($json, true); - if (json_last_error() !== JSON_ERROR_NONE) { - throw new InvalidJsonException(); - } - $doc = new self(); - if (isset($array['company'])) { - $doc->setCompany(new Company( - $array['company']['sno'] ?? null, - $array['company']['inn'] ?? null, - $array['company']['payment_address'] ?? null, - $array['company']['email'] ?? null - )); - } - if (isset($array['client'])) { - $doc->setClient(new Client( - $array['client']['name'] ?? null, - $array['client']['phone'] ?? null, - $array['client']['email'] ?? null, - $array['client']['inn'] ?? null - )); - } - if (isset($array['correction_info'])) { - $doc->setCorrectionInfo(new todoCorrectionInfo( - $array['correction_info']['type'] ?? null, - $array['correction_info']['base_date'] ?? null, - $array['correction_info']['base_number'] ?? null, - $array['correction_info']['base_name'] ?? null, - )); - } - if (isset($array['items'])) { - foreach ($array['items'] as $ar_item) { - $item = new Item( - $ar_item['name'] ?? null, - $ar_item['price'] ?? null, - $ar_item['quantity'] ?? null, - $ar_item['measurement_unit'] ?? null, - $ar_item['vat']['type'] ?? null, - $ar_item['payment_object'] ?? null, - $ar_item['payment_method'] ?? null - ); - if (!empty($ar_item['user_data'])) { - $item->setUserData($ar_item['user_data'] ?? null); - } - $doc->addItem($item); - } - } - if (isset($array['payments'])) { - foreach ($array['payments'] as $ar_payment) { - $payment = new todoPayment(); - if (isset($ar_payment['type'])) { - $payment->setType($ar_payment['type']); - } - if (isset($ar_payment['sum'])) { - $payment->setSum($ar_payment['sum']); - } - $doc->payments->add($payment); - } - } - if (isset($array['vats'])) { - foreach ($array['vats'] as $vat_payment) { - $vat = new Vat(); - if (isset($vat_payment['type'])) { - $vat->setType($vat_payment['type']); - } - if (isset($vat_payment['sum'])) { - $vat->setSum($vat_payment['sum']); - } - $doc->vats->add($vat); - } - } - if (isset($array['total']) && $array['total'] != $doc->calcTotal()) { - throw new AtolException('Real total sum not equals to provided in JSON one'); - } - return $doc; - } - - /** - * Возвращает массив для кодирования в json - * - * @throws Exception - */ - public function jsonSerialize(): array - { - if ($this->getCompany()) { - $json['company'] = $this->getCompany()->jsonSerialize(); // обязательно - } - if ($this->getPayments()) { - $json['payments'] = $this->payments->jsonSerialize(); // обязательно - } - if ($this->getCashier()) { - $json['cashier'] = $this->getCashier(); - } - if ($this->getCorrectionInfo()) { - $json['correction_info'] = $this->getCorrectionInfo()->jsonSerialize(); // обязательно для коррекционных - } else { - if ($this->getClient()) { - $json['client'] = $this->getClient()->jsonSerialize(); // обязательно для некоррекционных - } - if ($this->getItems()) { - $json['items'] = $this->items->jsonSerialize(); // обязательно для некоррекционных - } - $json['total'] = $this->calcTotal(); // обязательно для некоррекционных - } - if ($this->getVats()) { - $json['vats'] = $this->vats->jsonSerialize(); - } - return $json; - } -} diff --git a/src/Exceptions/EmptyAddUserPropNameException.php b/src/Exceptions/EmptyAddUserPropNameException.php index 567d18b..07f5d95 100644 --- a/src/Exceptions/EmptyAddUserPropNameException.php +++ b/src/Exceptions/EmptyAddUserPropNameException.php @@ -14,12 +14,12 @@ namespace AtolOnline\Exceptions; use AtolOnline\Constants\Ffd105Tags; /** - * Исключение, возникающее при пустом наименовании дополнительного реквизита + * Исключение, возникающее при пустом наименовании дополнительного реквизита пользователя * * @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32 */ class EmptyAddUserPropNameException extends AtolException { - protected $message = 'Наименование дополнительного реквизита не может быть пустым'; + protected $message = 'Наименование дополнительного реквизита пользователя не может быть пустым'; protected array $ffd_tags = [Ffd105Tags::DOC_ADD_USER_PROP_NAME]; } diff --git a/src/Exceptions/EmptyAddUserPropValueException.php b/src/Exceptions/EmptyAddUserPropValueException.php index d518bd6..4f7d8c2 100644 --- a/src/Exceptions/EmptyAddUserPropValueException.php +++ b/src/Exceptions/EmptyAddUserPropValueException.php @@ -14,12 +14,12 @@ namespace AtolOnline\Exceptions; use AtolOnline\Constants\Ffd105Tags; /** - * Исключение, возникающее при пустом наименовании дополнительного реквизита + * Исключение, возникающее при пустом наименовании дополнительного реквизита пользователя * * @see https://online.atol.ru/files/API_atol_online_v4.pdf Документация, стр 32 */ class EmptyAddUserPropValueException extends AtolException { - protected $message = 'Значение дополнительного реквизита не может быть пустым'; - protected array $ffd_tags = [Ffd105Tags::DOC_ADD_USER_PROP_NAME]; + protected $message = 'Значение дополнительного реквизита пользователя не может быть пустым'; + protected array $ffd_tags = [Ffd105Tags::DOC_ADD_USER_PROP_VALUE]; } diff --git a/src/Exceptions/TooLongAddCheckPropException.php b/src/Exceptions/TooLongAddCheckPropException.php new file mode 100644 index 0000000..1803b5e --- /dev/null +++ b/src/Exceptions/TooLongAddCheckPropException.php @@ -0,0 +1,28 @@ +