atol-online/src/Entities/todo_Document.php

469 lines
14 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<?php
/*
* Copyright (c) 2020-2021 Антон Аксенов (Anthony Axenov)
*
* This code is licensed under MIT.
* Этот код распространяется по лицензии MIT.
* https://github.com/anthonyaxenov/atol-online/blob/master/LICENSE
*/
declare(strict_types = 1);
namespace AtolOnline\Entities;
use AtolOnline\Constants\Constraints;
use AtolOnline\Exceptions\AtolException;
use AtolOnline\Exceptions\InvalidEmailException;
use AtolOnline\Exceptions\InvalidInnLengthException;
use AtolOnline\Exceptions\InvalidJsonException;
use AtolOnline\Exceptions\TooHighPriceException;
use AtolOnline\Exceptions\TooLongCashierException;
use AtolOnline\Exceptions\TooLongClientContactException;
use AtolOnline\Exceptions\TooLongEmailException;
use AtolOnline\Exceptions\TooLongItemNameException;
use AtolOnline\Exceptions\TooLongMeasurementUnitException;
use AtolOnline\Exceptions\TooLongPaymentAddressException;
use AtolOnline\Exceptions\TooLongUserdataException;
use AtolOnline\Exceptions\TooManyException;
use AtolOnline\Exceptions\TooManyItemsException;
use AtolOnline\Exceptions\TooManyPaymentsException;
use AtolOnline\Exceptions\TooManyVatsException;
use Exception;
/**
* Класс, описывающий документ
*
* @package AtolOnline\Entities
*/
class todoDocument extends Entity
{
/**
* @var ItemArray Массив предметов расчёта
*/
protected ItemArray $items;
/**
* @var VatArray Массив ставок НДС
*/
protected VatArray $vats;
/**
* @var PaymentArray Массив оплат
*/
protected PaymentArray $payments;
/**
* @var Company Объект компании (продавца)
*/
protected Company $company;
/**
* @var Client Объект клиента (покупателя)
*/
protected Client $client;
/**
* @var float Итоговая сумма чека. Тег ФФД - 1020.
*/
protected float $total = 0;
/**
* @var string ФИО кассира. Тег ФФД - 1021.
*/
protected string $cashier;
/**
* @var todoCorrectionInfo Данные коррекции
*/
protected todoCorrectionInfo $correction_info;
/**
* todoDocument constructor.
*/
public function __construct()
{
$this->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;
}
}