Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

310 rindas
9.2KB

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