158 خطوط
7.9 KiB
PHP
158 خطوط
7.9 KiB
PHP
<?php
|
|
|
|
namespace App\Services;
|
|
|
|
use App\Models\Invoice;
|
|
use Illuminate\Support\Facades\Storage;
|
|
use PhpOffice\PhpWord\PhpWord;
|
|
use PhpOffice\PhpWord\Shared\Converter;
|
|
use PhpOffice\PhpWord\SimpleType\JcTable;
|
|
|
|
class InvoiceWordService
|
|
{
|
|
public function create(Invoice $invoice): array
|
|
{
|
|
$invoice->loadMissing('creator:id,name');
|
|
$phpWord = new PhpWord;
|
|
$phpWord->setDefaultFontName('B Nazanin');
|
|
$phpWord->setDefaultFontSize(11);
|
|
|
|
$section = $phpWord->addSection([
|
|
'pageSizeW' => Converter::cmToTwip(21),
|
|
'pageSizeH' => Converter::cmToTwip(29.7),
|
|
'marginTop' => Converter::cmToTwip(1.2),
|
|
'marginRight' => Converter::cmToTwip(1.2),
|
|
'marginBottom' => Converter::cmToTwip(1.2),
|
|
'marginLeft' => Converter::cmToTwip(1.2),
|
|
]);
|
|
|
|
$rtl = ['alignment' => 'right', 'bidi' => true, 'spaceAfter' => 0];
|
|
$center = ['alignment' => 'center', 'bidi' => true, 'spaceAfter' => 0];
|
|
$font = ['name' => 'B Nazanin', 'size' => 11];
|
|
$bold = $font + ['bold' => true];
|
|
$heading = $font + ['bold' => true, 'size' => 17, 'color' => '172554'];
|
|
$headerCell = ['bgColor' => '172554', 'valign' => 'center'];
|
|
$borderCell = ['borderSize' => 4, 'borderColor' => '94A3B8', 'valign' => 'center'];
|
|
|
|
$section->addText('فاکتور فروش', $heading, $center);
|
|
$section->addTextBreak(1);
|
|
|
|
$meta = $section->addTable(['alignment' => JcTable::CENTER, 'width' => 100 * 50, 'unit' => 'pct', 'borderSize' => 4, 'borderColor' => '94A3B8']);
|
|
$meta->addRow(520);
|
|
$this->addLabelValue($meta, 'شماره فاکتور', $invoice->number ?: '—', $headerCell, $borderCell, $font, $bold);
|
|
$this->addLabelValue($meta, 'تاریخ صدور', $this->date($invoice->issued_at ?? $invoice->created_at), $headerCell, $borderCell, $font, $bold);
|
|
|
|
$this->addSectionTitle($section, 'مشخصات فروشنده', $headerCell, $bold);
|
|
$this->addPartyTable($section, $invoice->seller_snapshot ?: ['name' => $invoice->creator?->name], $font, $bold, $borderCell);
|
|
$this->addSectionTitle($section, 'مشخصات خریدار', $headerCell, $bold);
|
|
$this->addPartyTable($section, $invoice->customer_snapshot ?: [], $font, $bold, $borderCell);
|
|
|
|
$this->addSectionTitle($section, 'مشخصات کالا یا خدمات', $headerCell, $bold);
|
|
$items = $section->addTable(['alignment' => JcTable::CENTER, 'width' => 100 * 50, 'unit' => 'pct', 'borderSize' => 4, 'borderColor' => '94A3B8']);
|
|
$items->addRow(520);
|
|
foreach (['ردیف', 'شرح کالا یا خدمت', 'واحد', 'تعداد', 'مبلغ واحد', 'مبلغ کل'] as $index => $label) {
|
|
$widths = [700, 4300, 900, 900, 1600, 1800];
|
|
$items->addCell($widths[$index], $headerCell)->addText($label, $bold + ['color' => 'FFFFFF'], $center);
|
|
}
|
|
foreach (array_values($invoice->items ?: []) as $index => $item) {
|
|
$items->addRow(500);
|
|
$values = [
|
|
$index + 1,
|
|
$item['description'] ?? '—',
|
|
$item['unit'] ?? 'عدد',
|
|
$this->number($item['quantity'] ?? 0),
|
|
$this->money($item['unit_price'] ?? 0),
|
|
$this->money($item['line_total'] ?? 0),
|
|
];
|
|
foreach ($values as $column => $value) {
|
|
$widths = [700, 4300, 900, 900, 1600, 1800];
|
|
$items->addCell($widths[$column], $borderCell)->addText((string) $value, $font, $column === 1 ? $rtl : $center);
|
|
}
|
|
}
|
|
|
|
$section->addTextBreak(1);
|
|
$totals = $section->addTable(['alignment' => JcTable::END, 'width' => 55 * 50, 'unit' => 'pct', 'borderSize' => 4, 'borderColor' => '94A3B8']);
|
|
foreach ([
|
|
'جمع اقلام' => $invoice->subtotal,
|
|
'تخفیف' => $invoice->discount,
|
|
'مالیات و عوارض' => $invoice->tax,
|
|
'مبلغ نهایی' => $invoice->total,
|
|
'پرداختشده' => $invoice->paid_amount,
|
|
'مانده قابل پرداخت' => max(0, (float) $invoice->total - (float) $invoice->paid_amount),
|
|
] as $label => $value) {
|
|
$totals->addRow(480);
|
|
$totals->addCell(2400, $headerCell)->addText($label, $bold + ['color' => 'FFFFFF'], $rtl);
|
|
$totals->addCell(2600, $borderCell)->addText($this->money($value).' ریال', $bold, $rtl);
|
|
}
|
|
|
|
if ($invoice->payment_terms) {
|
|
$this->addSectionTitle($section, 'شرایط پرداخت', $headerCell, $bold);
|
|
$section->addText($invoice->payment_terms, $font, $rtl);
|
|
}
|
|
if ($invoice->notes) {
|
|
$this->addSectionTitle($section, 'توضیحات', $headerCell, $bold);
|
|
$section->addText($invoice->notes, $font, $rtl);
|
|
}
|
|
|
|
$section->addTextBreak(2);
|
|
$signature = $section->addTable(['alignment' => JcTable::CENTER, 'width' => 100 * 50, 'unit' => 'pct']);
|
|
$signature->addRow(900);
|
|
$signature->addCell(5000)->addText('مهر و امضای فروشنده', $bold, $center);
|
|
$signature->addCell(5000)->addText('مهر و امضای خریدار', $bold, $center);
|
|
|
|
Storage::disk('local')->makeDirectory('invoice-exports');
|
|
$filename = "invoice-{$invoice->number}.docx";
|
|
$path = Storage::disk('local')->path('invoice-exports/'.uniqid('invoice-', true).'.docx');
|
|
$phpWord->save($path, 'Word2007');
|
|
|
|
return compact('path', 'filename');
|
|
}
|
|
|
|
private function addSectionTitle($section, string $title, array $cellStyle, array $font): void
|
|
{
|
|
$section->addTextBreak(1);
|
|
$table = $section->addTable(['width' => 100 * 50, 'unit' => 'pct']);
|
|
$table->addRow(440);
|
|
$table->addCell(10000, $cellStyle)->addText($title, $font + ['color' => 'FFFFFF'], ['alignment' => 'center', 'bidi' => true, 'spaceAfter' => 0]);
|
|
}
|
|
|
|
private function addPartyTable($section, array $party, array $font, array $bold, array $cell): void
|
|
{
|
|
$table = $section->addTable(['alignment' => JcTable::CENTER, 'width' => 100 * 50, 'unit' => 'pct', 'borderSize' => 4, 'borderColor' => '94A3B8']);
|
|
$fields = [
|
|
['نام', $party['name'] ?? '—', 'نام/شرکت', $party['company'] ?? $party['name'] ?? '—'],
|
|
['شناسه/کد ملی', $party['national_code'] ?? $party['national_id'] ?? '—', 'کد اقتصادی', $party['economic_code'] ?? '—'],
|
|
['تلفن', $party['phone'] ?? '—', 'کد پستی', $party['postal_code'] ?? '—'],
|
|
['نشانی', $party['address'] ?? '—', 'ایمیل', $party['email'] ?? '—'],
|
|
];
|
|
foreach ($fields as [$label1, $value1, $label2, $value2]) {
|
|
$table->addRow(480);
|
|
foreach ([[$label1, $value1], [$label2, $value2]] as [$label, $value]) {
|
|
$table->addCell(1500, $cell + ['bgColor' => 'E2E8F0'])->addText($label, $bold, ['alignment' => 'right', 'bidi' => true, 'spaceAfter' => 0]);
|
|
$table->addCell(3500, $cell)->addText((string) $value, $font, ['alignment' => 'right', 'bidi' => true, 'spaceAfter' => 0]);
|
|
}
|
|
}
|
|
}
|
|
|
|
private function addLabelValue($table, string $label, string $value, array $headerCell, array $cell, array $font, array $bold): void
|
|
{
|
|
$table->addCell(1800, $headerCell)->addText($label, $bold + ['color' => 'FFFFFF'], ['alignment' => 'right', 'bidi' => true, 'spaceAfter' => 0]);
|
|
$table->addCell(3200, $cell)->addText($value, $font, ['alignment' => 'right', 'bidi' => true, 'spaceAfter' => 0]);
|
|
}
|
|
|
|
private function money(mixed $value): string
|
|
{
|
|
return number_format((float) $value, 0, '.', ',');
|
|
}
|
|
|
|
private function number(mixed $value): string
|
|
{
|
|
return rtrim(rtrim(number_format((float) $value, 2, '.', ''), '0'), '.');
|
|
}
|
|
|
|
private function date($value): string
|
|
{
|
|
return $value ? $value->format('Y/m/d') : '—';
|
|
}
|
|
}
|