Files
InvoiceShelf/app/Services/SerialNumberFormatter.php
mchev 3259173066 Laravel 11 (#84)
* Convert string references to `::class`

PHP 5.5.9 adds the new static `class` property which provides the fully qualified class name. This is preferred over using strings for class names since the `class` property references are checked by PHP.

* Use Faker methods

Accessing Faker properties was deprecated in Faker 1.14.

* Convert route options to fluent methods

Laravel 8 adopts the tuple syntax for controller actions. Since the old options array is incompatible with this syntax, Shift converted them to use modern, fluent methods.

* Adopt class based routes

* Remove default `app` files

* Shift core files

* Streamline config files

* Set new `ENV` variables

* Default new `bootstrap/app.php`

* Re-register HTTP middleware

* Consolidate service providers

* Re-register service providers

* Re-register routes

* Re-register scheduled commands

* Bump Composer dependencies

* Use `<env>` tags for configuration

`<env>` tags have a lower precedence than system environment variables making it easier to overwrite PHPUnit configuration values in additional environments, such a CI.

Review this blog post for more details on configuration precedence when testing Laravel: https://jasonmccreary.me/articles/laravel-testing-configuration-precedence/

* Adopt anonymous migrations

* Rename `password_resets` table

* Convert `$casts` property to method

* Adopt Laravel type hints

* Mark base controller as `abstract`

* Remove `CreatesApplication` testing trait

* Shift cleanup

* Fix shift first issues

* Updating Rules for laravel 11, sanctum config and pint

* Fix Carbon issue on dashboard

* Temporary fix for tests while migration is issue fixed on laravel side

* Carbon needs numerical values, not strings

* Minimum php version

* Fix domain installation step not fetching the correct company_id

* Fix Role Policy wasn't properly registered

---------
2024-06-05 11:33:52 +02:00

231 lines
5.7 KiB
PHP

<?php
namespace App\Services;
use App\Models\CompanySetting;
use App\Models\Customer;
/**
* SerialNumberFormatter
*/
class SerialNumberFormatter
{
public const VALID_PLACEHOLDERS = ['CUSTOMER_SERIES', 'SEQUENCE', 'DATE_FORMAT', 'SERIES', 'RANDOM_SEQUENCE', 'DELIMITER', 'CUSTOMER_SEQUENCE'];
private $model;
private $ob;
private $customer;
private $company;
/**
* @var string
*/
public $nextSequenceNumber;
/**
* @var string
*/
public $nextCustomerSequenceNumber;
/**
* @return $this
*/
public function setModel($model)
{
$this->model = $model;
return $this;
}
public function setModelObject($id = null)
{
$this->ob = $this->model::find($id);
if ($this->ob && $this->ob->sequence_number) {
$this->nextSequenceNumber = $this->ob->sequence_number;
}
if (isset($this->ob) && isset($this->ob->customer_sequence_number) && isset($this->customer) && $this->ob->customer_id == $this->customer->id) {
$this->nextCustomerSequenceNumber = $this->ob->customer_sequence_number;
}
return $this;
}
/**
* @return $this
*/
public function setCompany($company)
{
$this->company = $company;
return $this;
}
/**
* @return $this
*/
public function setCustomer($customer = null)
{
$this->customer = Customer::find($customer);
return $this;
}
/**
* @return string
*/
public function getNextNumber($data = null)
{
$modelName = strtolower(class_basename($this->model));
$settingKey = $modelName.'_number_format';
$companyId = $this->company;
if (request()->has('format')) {
$format = request()->get('format');
} else {
$format = CompanySetting::getSetting(
$settingKey,
$companyId
);
}
$this->setNextNumbers();
$serialNumber = $this->generateSerialNumber(
$format
);
return $serialNumber;
}
public function setNextNumbers()
{
$this->nextSequenceNumber ?
$this->nextSequenceNumber : $this->setNextSequenceNumber();
$this->nextCustomerSequenceNumber ?
$this->nextCustomerSequenceNumber : $this->setNextCustomerSequenceNumber();
return $this;
}
/**
* @return $this
*/
public function setNextSequenceNumber()
{
$companyId = $this->company;
$last = $this->model::orderBy('sequence_number', 'desc')
->where('company_id', $companyId)
->where('sequence_number', '<>', null)
->take(1)
->first();
$this->nextSequenceNumber = ($last) ? $last->sequence_number + 1 : 1;
return $this;
}
/**
* @return self
*/
public function setNextCustomerSequenceNumber()
{
$customer_id = ($this->customer) ? $this->customer->id : 1;
$last = $this->model::orderBy('customer_sequence_number', 'desc')
->where('company_id', $this->company)
->where('customer_id', $customer_id)
->where('customer_sequence_number', '<>', null)
->take(1)
->first();
$this->nextCustomerSequenceNumber = ($last) ? $last->customer_sequence_number + 1 : 1;
return $this;
}
public static function getPlaceholders(string $format)
{
$regex = '/{{([A-Z_]{1,})(?::)?([a-zA-Z0-9_]{1,6}|.{1})?}}/';
preg_match_all($regex, $format, $placeholders);
array_shift($placeholders);
$validPlaceholders = collect();
/** @var array */
$mappedPlaceholders = array_map(
null,
current($placeholders),
end($placeholders)
);
foreach ($mappedPlaceholders as $placeholder) {
$name = current($placeholder);
$value = end($placeholder);
if (in_array($name, self::VALID_PLACEHOLDERS)) {
$validPlaceholders->push([
'name' => $name,
'value' => $value,
]);
}
}
return $validPlaceholders;
}
/**
* @return string
*/
private function generateSerialNumber(string $format)
{
$serialNumber = '';
$placeholders = self::getPlaceholders($format);
foreach ($placeholders as $placeholder) {
$name = $placeholder['name'];
$value = $placeholder['value'];
switch ($name) {
case 'SEQUENCE':
$value = $value ? $value : 6;
$serialNumber .= str_pad($this->nextSequenceNumber, $value, 0, STR_PAD_LEFT);
break;
case 'DATE_FORMAT':
$value = $value ? $value : 'Y';
$serialNumber .= date($value);
break;
case 'RANDOM_SEQUENCE':
$value = $value ? $value : 6;
$serialNumber .= substr(bin2hex(random_bytes($value)), 0, $value);
break;
case 'CUSTOMER_SERIES':
if (isset($this->customer)) {
$serialNumber .= $this->customer->prefix ?? 'CST';
} else {
$serialNumber .= 'CST';
}
break;
case 'CUSTOMER_SEQUENCE':
$serialNumber .= str_pad($this->nextCustomerSequenceNumber, $value, 0, STR_PAD_LEFT);
break;
default:
$serialNumber .= $value;
}
}
return $serialNumber;
}
}