No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

290 líneas
8.7KB

  1. <?php
  2. namespace App\Logic;
  3. use App\Exceptions\AppCommonException;
  4. use App\Exceptions\GeneralErrorMessageException;
  5. use App\Files\PDF\Receipt as ReceiptReceipt;
  6. use App\Kintone\Models\Customer;
  7. use App\Kintone\Models\DropDown\PaymentPlan\PaymentType;
  8. use App\Kintone\Models\PaymentPlan;
  9. use App\Kintone\Models\Receipt;
  10. use App\Kintone\Models\SubTable\Receipt\PaymentPlan as ReceiptPaymentPlan;
  11. use App\Kintone\Models\SubTable\Receipt\ReceiptDetail;
  12. use App\Kintone\Models\SubTable\Receipt\TaxDetail;
  13. use App\Util\DateUtil;
  14. use App\Util\TaxUtil;
  15. use Exception;
  16. use Illuminate\Support\Collection;
  17. use PDF;
  18. class ReceiptManager
  19. {
  20. private ?Receipt $receipt = null;
  21. public function __construct(?int $recordNo = null)
  22. {
  23. if ($recordNo) {
  24. $this->load($recordNo);
  25. } else {
  26. $this->receipt = new Receipt();
  27. }
  28. }
  29. public function getReceipt(): Receipt
  30. {
  31. return $this->receipt;
  32. }
  33. public function create(array $paymentPlanRecordNoList)
  34. {
  35. // 支払予定データの取得
  36. $payments = $this->getPayments($paymentPlanRecordNoList);
  37. $this->checkPayments($payments, count($paymentPlanRecordNoList));
  38. // 顧客取得
  39. $customer = Customer::findByCustomerCode($payments->first()->customerCode);
  40. $receipt = $this->receipt;
  41. $receipt->receiptNo = $this->getReceiptNo();
  42. $receipt->receiptDate = DateUtil::now();
  43. $receipt->invoiceNo = config("business.invoiceNo", "");
  44. $receipt->receiptName = $this->getReceiptName($payments);
  45. $receipt->customerCode = $customer->customerCode;
  46. $receipt->taxType = "内税";
  47. $receipt->receiptCustomerName = $customer->customerName;
  48. $receipt->receiptTotalAmount = 0;
  49. // 明細------------
  50. foreach ($payments as $payment) {
  51. $detail = new ReceiptDetail();
  52. $detail->name = $payment->paymentType;
  53. $detail->parkingName = $payment->parkingName;
  54. $detail->unitPrice = $payment->appropriationAmount;
  55. $detail->quantity = 1;
  56. $detail->amount = $detail->unitPrice * $detail->quantity;
  57. $detail->targetMonth = $payment->targetMonth ? sprintf("%d月分", $payment->targetMonth) : "";
  58. $detail->taxRate = config("business.taxRate.normal", 0);
  59. $detail->memo = "memo";
  60. $receipt->receiptDetail->push($detail);
  61. $receipt->receiptTotalAmount += $payment->appropriationAmount;
  62. }
  63. // 内税明細--------------
  64. foreach ($receipt->receiptDetail as $detail) {
  65. $tax = $receipt->taxDetail->first(function (TaxDetail $ele) use ($detail) {
  66. return $ele->taxRate === $detail->taxRate;
  67. });
  68. if ($tax === null) {
  69. $tax = new TaxDetail();
  70. $tax->taxRate = $detail->taxRate;
  71. $receipt->taxDetail->push($tax);
  72. }
  73. if ($tax instanceof TaxDetail) {
  74. $tax->totalAmount += $detail->amount;
  75. }
  76. }
  77. // 税率の昇順に並び替え
  78. $receipt->taxDetail->sort(function (TaxDetail $a, TaxDetail $b) {
  79. return $a->taxRate < $b->taxRate ? -1 : 1;
  80. });
  81. // 内税計算
  82. foreach ($receipt->taxDetail as $detail) {
  83. $detail->taxAmount = TaxUtil::calcInnerTaxAmount($detail->totalAmount, $detail->taxRate);
  84. }
  85. // 入金実績---------------
  86. foreach ($payments as $payment) {
  87. $detail = new ReceiptPaymentPlan();
  88. $detail->recordNo = $payment->getRecordId();
  89. $receipt->paymentPlans->push($detail);
  90. }
  91. $receipt->save();
  92. return $this;
  93. }
  94. private function getPayments(array $paymentPlanRecordNoList)
  95. {
  96. $query = PaymentPlan::getQuery()->whereIn(PaymentPlan::FIELD_RECORD_NO, $paymentPlanRecordNoList);
  97. $ret = PaymentPlan::getAccess()->all($query);
  98. return $ret;
  99. }
  100. /**
  101. * @param Collection<int, PaymentPlan> $payments
  102. * @return void
  103. */
  104. private function checkPayments(Collection $payments, int $expectCount)
  105. {
  106. // データチェック
  107. if ($payments->isEmpty()) {
  108. throw new AppCommonException("支払予定検索0件");
  109. }
  110. if ($payments->count() !== $expectCount) {
  111. throw new AppCommonException(sprintf("件数不正 %d件 期待値:%d件 ", $payments->count(), $expectCount));
  112. }
  113. $customerCode = $payments->first()->customerCode;
  114. foreach ($payments as $payment) {
  115. if (!$payment->donePayment()) {
  116. throw new AppCommonException(sprintf("支払済みでない支払 %d ", $payment->getRecordId()));
  117. }
  118. if ($payment->customerCode !== $customerCode) {
  119. throw new AppCommonException(sprintf("単一の顧客コードのみ設定可能 %d or %d", $customerCode, $payment->customerCode));
  120. }
  121. }
  122. }
  123. /**
  124. * @param Collection<int, PaymentPlan> $payments
  125. * @return void
  126. */
  127. private function getReceiptName(Collection $payments): string
  128. {
  129. $seasonTicketCount = 0;
  130. $otherCount = 0;
  131. $otherName = "";
  132. foreach ($payments as $payment) {
  133. if ($payment->paymentType === PaymentType::SEASON_TICKET) {
  134. $seasonTicketCount++;
  135. } else {
  136. $otherCount++;
  137. $otherName = $payment->paymentType;
  138. }
  139. }
  140. if (0 < $seasonTicketCount && $otherCount === 0) {
  141. return "定期料金";
  142. }
  143. if (0 < $seasonTicketCount && 0 < $otherCount) {
  144. return "定期料金ほか";
  145. }
  146. return $otherName;
  147. }
  148. private function load(int $recordNo)
  149. {
  150. $this->receipt = Receipt::find($recordNo);
  151. }
  152. public function makePdf(): ReceiptReceipt
  153. {
  154. $pdf = $this->pdf();
  155. $file = new ReceiptReceipt();
  156. $file->setAppFileName($this->makeFileName($file))
  157. ->put($pdf->output());
  158. return $file;
  159. }
  160. public function savePdf()
  161. {
  162. if ($this->receipt === null) {
  163. throw new Exception("領収証不正");
  164. }
  165. $file = $this->makePdf();
  166. $access = Receipt::getAccess();
  167. $data = [];
  168. $data[] = [
  169. 'fileKey' => $access->filePut($file),
  170. 'name' => sprintf("領収証_%s.pdf", $this->receipt->receiptNo),
  171. 'contentType' => $file->getMimeType(),
  172. ];
  173. $this->receipt->set(Receipt::FIELD_RECEIPT_PDF_FILE, $data);
  174. $this->receipt->save();
  175. }
  176. public function getPdf()
  177. {
  178. $pdf = $this->pdf();
  179. if ($this->receipt->receiptPdfFileDownloadDatetime === null) {
  180. $this->receipt->receiptPdfFileDownloadDatetime = DateUtil::now();
  181. $this->savePdf();
  182. }
  183. return $pdf->inline();
  184. }
  185. private function pdf()
  186. {
  187. return PDF::loadView("pdf/receipt", $this->getPdfData())
  188. ->setPaper("A4")
  189. // ->setOption('page-width', 210)
  190. // ->setOption('page-height', 148)
  191. ->setOrientation("Portrait")
  192. ->setOption('encoding', 'utf-8');
  193. }
  194. public function getHtml()
  195. {
  196. return response()->view("pdf/receipt", ["forHtml" => true, ...$this->getPdfData()]);
  197. }
  198. private function makeFileName(ReceiptReceipt $file)
  199. {
  200. return sprintf(
  201. "領収証_%s_%s.%s",
  202. $this->receipt->receiptNo,
  203. $this->receipt->customerName,
  204. $file->getFileExtension(),
  205. );
  206. }
  207. private function getPdfData()
  208. {
  209. return [
  210. 'receiptDate' => $this->receipt->receiptDate->format('Y/m/d'),
  211. 'receiptCustomerName' => $this->receipt->receiptCustomerName,
  212. 'receiptTotalAmount' => number_format($this->receipt->receiptTotalAmount),
  213. 'taxTotalAmount' => $this->getTaxAmount10(),
  214. 'detail' => $this->receipt->receiptDetail,
  215. ];
  216. }
  217. private function getTaxAmount10(): int
  218. {
  219. $receipt = $this->receipt->taxDetail->first(function (TaxDetail $tax) {
  220. return $tax->taxRate === 10;
  221. });
  222. return $receipt ? $receipt->taxAmount : 0;
  223. }
  224. private function getReceiptNo(): string
  225. {
  226. /**
  227. * 申請番号を発番する。重複チェックを一定回数行う。
  228. */
  229. for ($i = 0; $i < 10; $i++) {
  230. $no = sprintf("%s-R%06d", DateUtil::now()->format('Ymd'), rand(1, 999999));
  231. $check = Receipt::getAccess()->some(Receipt::getQuery()->where(Receipt::FIELD_RECEIPT_NO, $no));
  232. if ($check->isEmpty()) {
  233. return $no;
  234. }
  235. }
  236. throw new AppCommonException('申請番号取得失敗');
  237. }
  238. }