Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

ExportService.php 10.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. <?php
  2. namespace App\Services;
  3. use App\Contracts\ExportableReport;
  4. use App\Contracts\HasSummaryReport;
  5. use App\Models\Company;
  6. use App\Transformers\CashFlowStatementReportTransformer;
  7. use Barryvdh\Snappy\Facades\SnappyPdf;
  8. use Carbon\Exceptions\InvalidFormatException;
  9. use Illuminate\Support\Carbon;
  10. use League\Csv\Bom;
  11. use League\Csv\CannotInsertRecord;
  12. use League\Csv\Exception;
  13. use League\Csv\Writer;
  14. use Symfony\Component\HttpFoundation\StreamedResponse;
  15. class ExportService
  16. {
  17. public function exportToCsv(Company $company, ExportableReport $report, ?string $startDate = null, ?string $endDate = null, ?string $activeTab = null): StreamedResponse
  18. {
  19. if ($startDate && $endDate) {
  20. $formattedStartDate = Carbon::parse($startDate)->toDateString();
  21. $formattedEndDate = Carbon::parse($endDate)->toDateString();
  22. $dateLabel = $formattedStartDate . ' to ' . $formattedEndDate;
  23. } else {
  24. $formattedAsOfDate = Carbon::parse($endDate)->toDateString();
  25. $dateLabel = $formattedAsOfDate;
  26. }
  27. $timestamp = Carbon::now()->format('Y-m-d_H-i-s');
  28. $filename = $company->name . ' ' . $report->getTitle() . ' ' . $dateLabel . ' ' . $timestamp . '.csv';
  29. $headers = [
  30. 'Content-Type' => 'text/csv',
  31. 'Content-Disposition' => 'attachment; filename="' . $filename . '"',
  32. ];
  33. $callback = function () use ($startDate, $endDate, $report, $company, $activeTab) {
  34. $csv = Writer::createFromStream(fopen('php://output', 'wb'));
  35. $csv->setOutputBOM(Bom::Utf8);
  36. if ($startDate && $endDate) {
  37. $defaultStartDateFormat = Carbon::parse($startDate)->toDefaultDateFormat();
  38. $defaultEndDateFormat = Carbon::parse($endDate)->toDefaultDateFormat();
  39. $dateLabel = 'Date Range: ' . $defaultStartDateFormat . ' to ' . $defaultEndDateFormat;
  40. } else {
  41. $dateLabel = 'As of ' . Carbon::parse($endDate)->toDefaultDateFormat();
  42. }
  43. $csv->insertOne([$report->getTitle()]);
  44. $csv->insertOne([$company->name]);
  45. $csv->insertOne([$dateLabel]);
  46. $csv->insertOne([]);
  47. if ($activeTab === 'summary') {
  48. $this->writeSummaryTableToCsv($csv, $report);
  49. } else {
  50. $this->writeDetailedTableToCsv($csv, $report);
  51. }
  52. };
  53. return response()->streamDownload($callback, $filename, $headers);
  54. }
  55. /**
  56. * @throws CannotInsertRecord
  57. * @throws Exception
  58. */
  59. protected function writeSummaryTableToCsv(Writer $csv, ExportableReport $report): void
  60. {
  61. /** @var HasSummaryReport $report */
  62. $csv->insertOne($report->getSummaryHeaders());
  63. foreach ($report->getSummaryCategories() as $category) {
  64. if (filled($category->header)) {
  65. $csv->insertOne($category->header);
  66. }
  67. foreach ($category->types ?? [] as $type) {
  68. $csv->insertOne($type->summary);
  69. }
  70. if (filled($category->summary)) {
  71. $csv->insertOne($category->summary);
  72. }
  73. if ($category->summary['account_name'] === 'Cost of Goods Sold' && method_exists($report, 'getGrossProfit') && filled($report->getGrossProfit())) {
  74. $csv->insertOne($report->getGrossProfit());
  75. }
  76. if (filled($category->header)) {
  77. $csv->insertOne([]);
  78. }
  79. }
  80. if (method_exists($report, 'getSummaryOverviewHeaders') && filled($report->getSummaryOverviewHeaders())) {
  81. $this->writeSummaryOverviewTableToCsv($csv, $report);
  82. }
  83. if (filled($report->getSummaryOverallTotals())) {
  84. $csv->insertOne($report->getSummaryOverallTotals());
  85. }
  86. }
  87. /**
  88. * @throws CannotInsertRecord
  89. * @throws Exception
  90. */
  91. protected function writeDetailedTableToCsv(Writer $csv, ExportableReport $report): void
  92. {
  93. $csv->insertOne($report->getHeaders());
  94. foreach ($report->getCategories() as $category) {
  95. $this->writeDataRowsToCsv($csv, $category->header, $category->data, $report->getColumns());
  96. foreach ($category->types ?? [] as $type) {
  97. $this->writeDataRowsToCsv($csv, $type->header, $type->data, $report->getColumns());
  98. if (filled($type->summary)) {
  99. $csv->insertOne($type->summary);
  100. }
  101. }
  102. if (filled($category->summary)) {
  103. $csv->insertOne($category->summary);
  104. }
  105. $csv->insertOne([]);
  106. }
  107. if (method_exists($report, 'getOverviewHeaders') && filled($report->getOverviewHeaders())) {
  108. $this->writeOverviewTableToCsv($csv, $report);
  109. }
  110. if (filled($report->getOverallTotals())) {
  111. $csv->insertOne($report->getOverallTotals());
  112. }
  113. }
  114. /**
  115. * @throws CannotInsertRecord
  116. * @throws Exception
  117. */
  118. protected function writeSummaryOverviewTableToCsv(Writer $csv, ExportableReport $report): void
  119. {
  120. /** @var CashFlowStatementReportTransformer $report */
  121. $headers = $report->getSummaryOverviewHeaders();
  122. if (filled($headers)) {
  123. $csv->insertOne($headers);
  124. }
  125. foreach ($report->getSummaryOverview() as $overviewCategory) {
  126. if (filled($overviewCategory->header)) {
  127. $this->writeDataRowsToCsv($csv, $overviewCategory->header, $overviewCategory->data, $report->getSummaryColumns());
  128. }
  129. if (filled($overviewCategory->summary)) {
  130. $csv->insertOne($overviewCategory->summary);
  131. }
  132. if ($overviewCategory->summary['account_name'] === 'Starting Balance') {
  133. foreach ($report->getSummaryOverviewAlignedWithColumns() as $summaryRow) {
  134. $row = [];
  135. foreach ($report->getSummaryColumns() as $column) {
  136. $columnName = $column->getName();
  137. $row[] = $summaryRow[$columnName] ?? '';
  138. }
  139. if (array_filter($row)) {
  140. $csv->insertOne($row);
  141. }
  142. }
  143. }
  144. }
  145. }
  146. /**
  147. * @throws CannotInsertRecord
  148. * @throws Exception
  149. */
  150. protected function writeOverviewTableToCsv(Writer $csv, ExportableReport $report): void
  151. {
  152. /** @var CashFlowStatementReportTransformer $report */
  153. $headers = $report->getOverviewHeaders();
  154. if (filled($headers)) {
  155. $csv->insertOne($headers);
  156. }
  157. foreach ($report->getOverview() as $overviewCategory) {
  158. if (filled($overviewCategory->header)) {
  159. $this->writeDataRowsToCsv($csv, $overviewCategory->header, $overviewCategory->data, $report->getColumns());
  160. }
  161. if (filled($overviewCategory->summary)) {
  162. $csv->insertOne($overviewCategory->summary);
  163. }
  164. if ($overviewCategory->header['account_name'] === 'Starting Balance') {
  165. foreach ($report->getOverviewAlignedWithColumns() as $summaryRow) {
  166. $row = [];
  167. foreach ($report->getColumns() as $column) {
  168. $columnName = $column->getName();
  169. $row[] = $summaryRow[$columnName] ?? '';
  170. }
  171. if (array_filter($row)) {
  172. $csv->insertOne($row);
  173. }
  174. }
  175. }
  176. }
  177. }
  178. /**
  179. * @throws CannotInsertRecord
  180. * @throws Exception
  181. */
  182. protected function writeDataRowsToCsv(Writer $csv, array $header, array $data, array $columns): void
  183. {
  184. if (isset($header[0]) && is_array($header[0])) {
  185. foreach ($header as $headerRow) {
  186. $csv->insertOne($headerRow);
  187. }
  188. } else {
  189. $csv->insertOne($header);
  190. }
  191. // Output data rows
  192. foreach ($data as $rowData) {
  193. $row = [];
  194. foreach ($columns as $column) {
  195. $columnName = $column->getName();
  196. $cell = $rowData[$columnName] ?? '';
  197. if ($column->isDate()) {
  198. try {
  199. $row[] = Carbon::parse($cell)->toDateString();
  200. } catch (InvalidFormatException) {
  201. $row[] = $cell;
  202. }
  203. } elseif (is_array($cell)) {
  204. $row[] = $cell['name'] ?? $cell['description'] ?? '';
  205. } else {
  206. $row[] = $cell;
  207. }
  208. }
  209. $csv->insertOne($row);
  210. }
  211. }
  212. public function exportToPdf(Company $company, ExportableReport $report, ?string $startDate = null, ?string $endDate = null, ?string $activeTab = null): StreamedResponse
  213. {
  214. if ($startDate && $endDate) {
  215. $formattedStartDate = Carbon::parse($startDate)->toDateString();
  216. $formattedEndDate = Carbon::parse($endDate)->toDateString();
  217. $dateLabel = $formattedStartDate . ' to ' . $formattedEndDate;
  218. } else {
  219. $formattedAsOfDate = Carbon::parse($endDate)->toDateString();
  220. $dateLabel = $formattedAsOfDate;
  221. }
  222. $timestamp = Carbon::now()->format('Y-m-d_H-i-s');
  223. $filename = $company->name . ' ' . $report->getTitle() . ' ' . $dateLabel . ' ' . $timestamp . '.pdf';
  224. $view = $activeTab === 'summary' ? $report->getSummaryPdfView() : $report->getPdfView();
  225. $pdf = SnappyPdf::loadView($view, [
  226. 'company' => $company,
  227. 'report' => $report,
  228. 'startDate' => $startDate ? Carbon::parse($startDate)->toDefaultDateFormat() : null,
  229. 'endDate' => $endDate ? Carbon::parse($endDate)->toDefaultDateFormat() : null,
  230. ]);
  231. return response()->streamDownload(function () use ($pdf) {
  232. echo $pdf->inline();
  233. }, $filename);
  234. }
  235. }