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

Invoice.php 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. <?php
  2. namespace App\Http\Livewire;
  3. use App\Abstracts\Forms\EditFormRecord;
  4. use App\Models\Setting\DocumentDefault;
  5. use Filament\Forms\ComponentContainer;
  6. use Filament\Forms\Components\ColorPicker;
  7. use Filament\Forms\Components\FileUpload;
  8. use Filament\Forms\Components\Group;
  9. use Filament\Forms\Components\Radio;
  10. use Filament\Forms\Components\Section;
  11. use Filament\Forms\Components\Select;
  12. use Filament\Forms\Components\Textarea;
  13. use Filament\Forms\Components\TextInput;
  14. use Filament\Forms\Components\ViewField;
  15. use Illuminate\Contracts\View\View;
  16. use Illuminate\Database\Eloquent\Model;
  17. /**
  18. * @property ComponentContainer $form
  19. */
  20. class Invoice extends EditFormRecord
  21. {
  22. public DocumentDefault $invoice;
  23. protected function getFormModel(): Model|string|null
  24. {
  25. $this->invoice = DocumentDefault::where('type', 'invoice')->firstOrNew();
  26. return $this->invoice;
  27. }
  28. public function mount(): void
  29. {
  30. $this->fillForm();
  31. }
  32. public function fillForm(): void
  33. {
  34. $data = $this->getFormModel()->attributesToArray();
  35. unset($data['id']);
  36. $data = $this->mutateFormDataBeforeFill($data);
  37. $this->form->fill($data);
  38. }
  39. protected function getFormSchema(): array
  40. {
  41. return [
  42. Section::make('General')
  43. ->schema([
  44. TextInput::make('number_prefix')
  45. ->label('Number Prefix')
  46. ->default('INV-')
  47. ->reactive()
  48. ->required(),
  49. Select::make('number_digits')
  50. ->label('Number Digits')
  51. ->options($this->invoice->getAvailableNumberDigits())
  52. ->default($this->invoice->getDefaultNumberDigits())
  53. ->reactive()
  54. ->afterStateUpdated(function (callable $set, $state) {
  55. $numDigits = $state;
  56. $nextNumber = $this->invoice->getNextDocumentNumber($numDigits);
  57. return $set('number_next', $nextNumber);
  58. })
  59. ->required()
  60. ->searchable(),
  61. TextInput::make('number_next')
  62. ->label('Next Number')
  63. ->reactive()
  64. ->required()
  65. ->default($this->invoice->getNextDocumentNumber($this->invoice->getDefaultNumberDigits())),
  66. Select::make('payment_terms')
  67. ->label('Payment Terms')
  68. ->options($this->invoice->getPaymentTerms())
  69. ->default($this->invoice->getDefaultPaymentTerms())
  70. ->searchable()
  71. ->reactive()
  72. ->required(),
  73. ])->columns(),
  74. Section::make('Content')
  75. ->schema([
  76. TextInput::make('title')
  77. ->label('Title')
  78. ->reactive()
  79. ->default('Invoice')
  80. ->nullable(),
  81. TextInput::make('subheading')
  82. ->label('Subheading')
  83. ->reactive()
  84. ->nullable(),
  85. Textarea::make('footer')
  86. ->label('Footer')
  87. ->reactive()
  88. ->nullable(),
  89. Textarea::make('terms')
  90. ->label('Notes / Terms')
  91. ->nullable()
  92. ->reactive(),
  93. ])->columns(),
  94. Section::make('Template Settings')
  95. ->description('Choose the template and edit the titles of the columns on your invoices.')
  96. ->schema([
  97. Group::make()
  98. ->schema([
  99. FileUpload::make('document_logo')
  100. ->label('Logo')
  101. ->disk('public')
  102. ->directory('logos/documents')
  103. ->imageResizeMode('contain')
  104. ->imagePreviewHeight('250')
  105. ->imageCropAspectRatio('2:1')
  106. ->reactive()
  107. ->enableOpen()
  108. ->preserveFilenames()
  109. ->visibility('public')
  110. ->image(),
  111. ColorPicker::make('accent_color')
  112. ->label('Accent Color')
  113. ->reactive()
  114. ->default('#d9d9d9'),
  115. Select::make('template')
  116. ->label('Template')
  117. ->options([
  118. 'default' => 'Default',
  119. 'modern' => 'Modern',
  120. ])
  121. ->reactive()
  122. ->default('modern')
  123. ->required(),
  124. Radio::make('item_column')
  125. ->label('Items')
  126. ->options($this->invoice->getItemColumns())
  127. ->dehydrateStateUsing(static function (callable $get, $state) {
  128. return $state === 'other' ? $get('custom_item_column') : $state;
  129. })
  130. ->afterStateHydrated(function (callable $set, callable $get, $state, Radio $component) {
  131. if (isset($this->invoice->getItemColumns()[$state])) {
  132. $component->state($state);
  133. } else {
  134. $component->state('other');
  135. $set('custom_item_column', $state);
  136. }
  137. })
  138. ->default($this->invoice->getDefaultItemColumn())
  139. ->reactive(),
  140. TextInput::make('custom_item_column')
  141. ->reactive()
  142. ->disableLabel()
  143. ->disabled(static fn (callable $get) => $get('item_column') !== 'other')
  144. ->nullable(),
  145. Radio::make('unit_column')
  146. ->label('Units')
  147. ->options(DocumentDefault::getUnitColumns())
  148. ->dehydrateStateUsing(static function (callable $get, $state) {
  149. return $state === 'other' ? $get('custom_unit_column') : $state;
  150. })
  151. ->afterStateHydrated(function (callable $set, callable $get, $state, Radio $component) {
  152. if (isset($this->invoice->getUnitColumns()[$state])) {
  153. $component->state($state);
  154. } else {
  155. $component->state('other');
  156. $set('custom_unit_column', $state);
  157. }
  158. })
  159. ->default($this->invoice->getDefaultUnitColumn())
  160. ->reactive(),
  161. TextInput::make('custom_unit_column')
  162. ->reactive()
  163. ->disableLabel()
  164. ->disabled(static fn (callable $get) => $get('unit_column') !== 'other')
  165. ->nullable(),
  166. Radio::make('price_column')
  167. ->label('Price')
  168. ->options($this->invoice->getPriceColumns())
  169. ->dehydrateStateUsing(static function (callable $get, $state) {
  170. return $state === 'other' ? $get('custom_price_column') : $state;
  171. })
  172. ->afterStateHydrated(function (callable $set, callable $get, $state, Radio $component) {
  173. if (isset($this->invoice->getPriceColumns()[$state])) {
  174. $component->state($state);
  175. } else {
  176. $component->state('other');
  177. $set('custom_price_column', $state);
  178. }
  179. })
  180. ->default($this->invoice->getDefaultPriceColumn())
  181. ->reactive(),
  182. TextInput::make('custom_price_column')
  183. ->reactive()
  184. ->disableLabel()
  185. ->disabled(static fn (callable $get) => $get('price_column') !== 'other')
  186. ->nullable(),
  187. Radio::make('amount_column')
  188. ->label('Amount')
  189. ->options($this->invoice->getAmountColumns())
  190. ->dehydrateStateUsing(static function (callable $get, $state) {
  191. return $state === 'other' ? $get('custom_amount_column') : $state;
  192. })
  193. ->afterStateHydrated(function (callable $set, callable $get, $state, Radio $component) {
  194. if (isset($this->invoice->getAmountColumns()[$state])) {
  195. $component->state($state);
  196. } else {
  197. $component->state('other');
  198. $set('custom_amount_column', $state);
  199. }
  200. })
  201. ->default($this->invoice->getDefaultAmountColumn())
  202. ->reactive(),
  203. TextInput::make('custom_amount_column')
  204. ->reactive()
  205. ->disableLabel()
  206. ->disabled(static fn (callable $get) => $get('amount_column') !== 'other')
  207. ->nullable(),
  208. ])->columns(1),
  209. Group::make()
  210. ->schema([
  211. ViewField::make('preview.default')
  212. ->label('Preview')
  213. ->visible(static fn (callable $get) => $get('template') === 'default')
  214. ->view('components.invoice-layouts.default'),
  215. ViewField::make('preview.modern')
  216. ->label('Preview')
  217. ->visible(static fn (callable $get) => $get('template') === 'modern')
  218. ->view('components.invoice-layouts.modern'),
  219. ])->columnSpan(2),
  220. ])->columns(3),
  221. ];
  222. }
  223. protected function mutateFormDataBeforeSave(array $data): array
  224. {
  225. $data['type'] = 'invoice';
  226. return $data;
  227. }
  228. public function render(): View
  229. {
  230. return view('livewire.invoice');
  231. }
  232. }