CRM/backend/app/Services/InvoiceWordService.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') : '—';
}
}