選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

DocumentDefault.php 6.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. <?php
  2. namespace App\Models\Setting;
  3. use App\Casts\TrimLeadingZeroCast;
  4. use App\Enums\{DocumentType, Font, PaymentTerms, Template};
  5. use App\Traits\{Blamable, CompanyOwned};
  6. use Database\Factories\Setting\DocumentDefaultFactory;
  7. use Illuminate\Database\Eloquent\Casts\AsArrayObject;
  8. use Illuminate\Database\Eloquent\Factories\{Factory, HasFactory};
  9. use Illuminate\Database\Eloquent\Relations\BelongsTo;
  10. use Illuminate\Database\Eloquent\{Builder, Model};
  11. use Wallo\FilamentCompanies\FilamentCompanies;
  12. class DocumentDefault extends Model
  13. {
  14. use Blamable;
  15. use CompanyOwned;
  16. use HasFactory;
  17. protected $table = 'document_defaults';
  18. protected $fillable = [
  19. 'company_id',
  20. 'type',
  21. 'logo',
  22. 'show_logo',
  23. 'number_prefix',
  24. 'number_digits',
  25. 'number_next',
  26. 'payment_terms',
  27. 'header',
  28. 'subheader',
  29. 'terms',
  30. 'footer',
  31. 'accent_color',
  32. 'font',
  33. 'template',
  34. 'item_name',
  35. 'unit_name',
  36. 'price_name',
  37. 'amount_name',
  38. 'created_by',
  39. 'updated_by',
  40. ];
  41. protected $casts = [
  42. 'show_logo' => 'boolean',
  43. 'number_next' => TrimLeadingZeroCast::class,
  44. 'payment_terms' => PaymentTerms::class,
  45. 'font' => Font::class,
  46. 'template' => Template::class,
  47. 'item_name' => AsArrayObject::class,
  48. 'unit_name' => AsArrayObject::class,
  49. 'price_name' => AsArrayObject::class,
  50. 'amount_name' => AsArrayObject::class,
  51. ];
  52. public function company(): BelongsTo
  53. {
  54. return $this->belongsTo(FilamentCompanies::companyModel(), 'company_id');
  55. }
  56. public function createdBy(): BelongsTo
  57. {
  58. return $this->belongsTo(FilamentCompanies::userModel(), 'created_by');
  59. }
  60. public function updatedBy(): BelongsTo
  61. {
  62. return $this->belongsTo(FilamentCompanies::userModel(), 'updated_by');
  63. }
  64. public function scopeType(Builder $query, string | DocumentType $type): Builder
  65. {
  66. return $query->where($this->qualifyColumn('type'), $type);
  67. }
  68. public function scopeInvoice(Builder $query): Builder
  69. {
  70. return $query->scopes(['type' => [DocumentType::Invoice]]);
  71. }
  72. public function scopeBill(Builder $query): Builder
  73. {
  74. return $query->scopes(['type' => [DocumentType::Bill]]);
  75. }
  76. public static function availableNumberDigits(): array
  77. {
  78. return array_combine(range(1, 20), range(1, 20));
  79. }
  80. public static function getNumberNext(?bool $padded = null, ?bool $format = null, ?string $prefix = null, int | string | null $digits = null, int | string | null $next = null, ?string $type = null): string
  81. {
  82. $initializeAttributes = new static;
  83. [$number_prefix, $number_digits, $number_next] = $initializeAttributes->initializeAttributes($prefix, $digits, $next, $type);
  84. if ($format) {
  85. return $number_prefix . static::getPaddedNumberNext($number_next, $number_digits);
  86. }
  87. if ($padded) {
  88. return static::getPaddedNumberNext($number_next, $number_digits);
  89. }
  90. return $number_next;
  91. }
  92. public function initializeAttributes(?string $prefix, int | string | null $digits, int | string | null $next, ?string $type): array
  93. {
  94. $number_prefix = $prefix ?? $this->getAttributeFromArray('number_prefix');
  95. $number_digits = $digits ?? $this->getAttributeFromArray('number_digits');
  96. $number_next = $next ?? $this->getAttributeFromArray('number_next');
  97. if ($type) {
  98. $attributes = static::getAttributesByType($type);
  99. $number_prefix = $attributes['number_prefix'] ?? $number_prefix;
  100. $number_digits = $attributes['number_digits'] ?? $number_digits;
  101. $number_next = $attributes['number_next'] ?? $number_next;
  102. }
  103. return [$number_prefix, $number_digits, $number_next];
  104. }
  105. public static function getAttributesByType(?string $type): array
  106. {
  107. $model = new static;
  108. $attributes = $model->newQuery()->type($type)->first();
  109. return $attributes ? $attributes->toArray() : [];
  110. }
  111. /**
  112. * Get the next number with padding for dynamic display purposes.
  113. * Even if number_next is a string, it will be cast to an integer.
  114. */
  115. public static function getPaddedNumberNext(int | string | null $number_next, int | string | null $number_digits): string
  116. {
  117. return str_pad($number_next, $number_digits, '0', STR_PAD_LEFT);
  118. }
  119. public function getItemNameOptionAttribute(): ?string
  120. {
  121. return $this->item_name['option'] ?? null;
  122. }
  123. public function getItemNameCustomAttribute(): ?string
  124. {
  125. return $this->item_name['custom'] ?? null;
  126. }
  127. public function getItemNameOptions(): array
  128. {
  129. return $this->item_name ?? [];
  130. }
  131. public function getUnitNameOptionAttribute(): ?string
  132. {
  133. return $this->unit_name['option'] ?? null;
  134. }
  135. public function getUnitNameCustomAttribute(): ?string
  136. {
  137. return $this->unit_name['custom'] ?? null;
  138. }
  139. public function getUnitNameOptions(): array
  140. {
  141. return $this->unit_name ?? [];
  142. }
  143. public function getPriceNameOptionAttribute(): ?string
  144. {
  145. return $this->price_name['option'] ?? null;
  146. }
  147. public function getPriceNameCustomAttribute(): ?string
  148. {
  149. return $this->price_name['custom'] ?? null;
  150. }
  151. public function getPriceNameOptions(): array
  152. {
  153. return $this->price_name ?? [];
  154. }
  155. public function getAmountNameOptionAttribute(): ?string
  156. {
  157. return $this->amount_name['option'] ?? null;
  158. }
  159. public function getAmountNameCustomAttribute(): ?string
  160. {
  161. return $this->amount_name['custom'] ?? null;
  162. }
  163. public function getAmountNameOptions(): array
  164. {
  165. return $this->amount_name ?? [];
  166. }
  167. public static function getAvailableItemNameOptions(): array
  168. {
  169. return [
  170. 'items' => 'Items',
  171. 'products' => 'Products',
  172. 'services' => 'Services',
  173. 'other' => 'Other',
  174. ];
  175. }
  176. public static function getAvailableUnitNameOptions(): array
  177. {
  178. return [
  179. 'quantity' => 'Quantity',
  180. 'hours' => 'Hours',
  181. 'other' => 'Other',
  182. ];
  183. }
  184. public static function getAvailablePriceNameOptions(): array
  185. {
  186. return [
  187. 'price' => 'Price',
  188. 'rate' => 'Rate',
  189. 'other' => 'Other',
  190. ];
  191. }
  192. public static function getAvailableAmountNameOptions(): array
  193. {
  194. return [
  195. 'amount' => 'Amount',
  196. 'total' => 'Total',
  197. 'other' => 'Other',
  198. ];
  199. }
  200. protected static function newFactory(): Factory
  201. {
  202. return DocumentDefaultFactory::new();
  203. }
  204. }