trinion_mrp-1.0.x-dev/src/Form/MrpRecordCreatorForm.php
src/Form/MrpRecordCreatorForm.php
<?php
declare(strict_types=1);
namespace Drupal\trinion_mrp\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\node\Entity\Node;
use Drupal\trinion_mrp\Controller\SozdanieZakazaNaProizvodstvo;
use Drupal\trinion_mrp\Controller\SozdanieZakazaPostavshiku;
/**
* Мастер создания MRP записей
*/
final class MrpRecordCreatorForm extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId(): string {
return 'trinion_mrp_record_creator';
}
/**
* {@inheritdoc}
*/
public function buildForm(array $form, FormStateInterface $form_state): array {
$form['scenario'] = [
'#type' => 'entity_autocomplete',
'#title' => t('Scenario'),
'#required' => TRUE,
'#target_type' => 'node',
'#selection_settings' => [
'target_bundles' => ['mrp_scenario'],
],
];
$tree = \Drupal::entityTypeManager()->getStorage('taxonomy_term')->loadTree('sklad');
$options = [];
foreach ($tree as $item)
$options[$item->tid] = $item->name;
$form['sklad'] = [
'#type' => 'select',
'#title' => t('Warehouse'),
'#multiple' => TRUE,
'#required' => TRUE,
'#options' => $options,
];
$form['mps'] = [
'#type' => 'entity_autocomplete',
'#title' => t('MPS'),
'#target_type' => 'node',
'#required' => TRUE,
'#selection_settings' => [
'target_bundles' => ['mps'],
],
];
// $form['show_table'] = [
// '#type' => 'submit',
// '#value' => t('Show table'),
// '#submit' => ['::showTableSubmit'],
// ];
$form['actions']['submit'] = [
'#type' => 'actions',
'submit' => [
'#type' => 'submit',
'#value' => $this->t('Show MRP Records'),
'#submit' => ['::showMrpRecordsSubmit']
],
];
// if ($products = $form_state->get('products')) {
// $form['table'] = [
// '#type' => 'container',
// '#custom_suggestion' => 'gross_requirements',
// '#tree' => TRUE,
// ];
//
// foreach ($products as $key => $product) {
// $form['table']['periods'][$key]['#product_data'] = $product;
// foreach ($product['periods'] as $i => $count) {
// $form['table']['periods'][$key][$i] = [
// '#type' => 'number',
// '#caption' => $i,
// '#default_value' => $i == 1 ? $count : '',
// ];
// }
// }
//
// $form['table']['periods'] = array_values($form['table']['periods']);
// }
$records = $form_state->get('records');
if ($records) {
$form['tables'] = [
'#type' => 'container',
'#prefix' => '<hr><h2>' . t('MRP records preview') . '</h2>',
];
foreach ($records as $record) {
$form['tables'][] = self::tableElement($record);
}
$form['save_mrp_records_submit'] = [
'#type' => 'submit',
'#value' => t('Save MRP records, PuO, PrO'),
'#submit' => ['::saveMrpRecordsSubmit'],
];
if (!\Drupal::state()->get('trinion_mrp_proizvodstvenniy_kalendar')) {
$form['save_mrp_records_submit']['#disabled'] = TRUE;
$form['save_mrp_records_submit']['#suffix'] = t('The production calendar has not been formed');
}
}
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state): void {
}
public function showMrpRecordsSubmit(array &$form, FormStateInterface $form_state): void {
$values = $form_state->getValues();
$mps = Node::load($values['mps']);
$product_periods = [];
foreach ($mps->get('field_tp_stroki') as $stroka) {
$stroka = $stroka->entity;
$tovar = $stroka->get('field_tp_tovar')->first()->entity;
$tovar_name = $tovar->get('field_tp_artikul')->getString();
$key = $tovar->id();
if ($harakteristika = $stroka->get('field_tp_kharakteristika_tovara')->first()) {
$tovar_name .= ', ' . $harakteristika->entity->label();
$key .= '_' . $harakteristika->id();
}
if (!isset($product_periods[$key])) {
$product_periods[$key]['tovar'] = $tovar;
$product_periods[$key]['unit'] = $stroka->get('field_tp_edinica_izmereniya')->first()->entity->id();
$product_periods[$key]['harakteristika'] = $harakteristika ? $harakteristika : NULL;
$product_periods[$key]['product_name'] = $tovar_name;
}
$product_periods[$key]['source'][] = $values['mps'];
$product_periods[$key]['periods'] = $stroka->periods;
}
$product_periods = array_values($product_periods);
$records = [];
foreach ($product_periods as $key => $product) {
$records = $this->generateMrpRecordData($product, $values['sklad'], $records, $product['periods'], $mps->get('field_mrp_period_length_days')->getString(), 1, TRUE);
}
$form_state->setRebuild(TRUE);
$form_state->set('records', $records);
}
public function generateMrpRecordData($product, $skladi, $records, $planed_order_receipts, $periods_length, $level, $recursive) {
static $sklad_kolichestvo = [];
$has_error = FALSE;
$tovar = $product['tovar'];
$record = $product;
$record['harakteristika_tid'] = $harakteristika_tid = $product['harakteristika'] ? $product['harakteristika']->id() : NULL;
$record['part'] = $product['product_name'];
$record['source'] = $product['source'];
$record['tovar'] = $tovar;
$record['level'] = $level;
$record['kolichestvo'] = $product['kolichestvo'] ?? 1;
$edinica_izmereniya_tid = $product['unit'];
$record['leadtime'] = $tovar->get('field_mrp_lead_time')->getString();
$lot_size = $tovar->get('field_mrp_lot_size')->getString();
if ($lot_size == '') {
$has_error = TRUE;
\Drupal::messenger()->addError(t('Part %part. Lot Size is not specified.', ['%part' => $record['part']]));
}
else {
$mrp_lot_size_spisok_znacheniy = $tovar->field_mrp_lot_size->getSetting('allowed_values');
$record['lotsize'] = $mrp_lot_size_spisok_znacheniy[$tovar->get('field_mrp_lot_size')->getString()];
if ($record['lotsize'])
$record['lotsize_value'] = $tovar->get('field_mrp_lotsize_value')->getString();
}
$tovar_id = $tovar->id();
if (isset($sklad_kolichestvo[$tovar_id][$harakteristika_tid][$edinica_izmereniya_tid])) {
$available_balance = $sklad_kolichestvo[$tovar_id][$harakteristika_tid][$edinica_izmereniya_tid];
if ($available_balance < 0)
$available_balance = 0;
}
else {
$available_balance = 0;
foreach ($skladi as $sklad_tid) {
$available_balance += \Drupal::service('trinion_tp.helper')->getLiveOstatok($tovar_id, $sklad_tid, $harakteristika_tid, $edinica_izmereniya_tid);
}
}
$record['available_balance_start'] = $available_balance;
$record['gross_requirements'] = $planed_order_receipts;
foreach ($record['gross_requirements'] as $period => $count) {
$record['planned_order_released'][$period] = '';
$record['planed_order_receipts'][$period] = '';
if ($count) {
if ($available_balance < 0) {
$record['planed_order_receipts'][$period] = $count;
$available_balance -= $count;
}
else {
$available_balance -= $count;
if ($available_balance < 0) {
$record['planed_order_receipts'][$period] = -1 * $available_balance;
}
}
$record['available_balance'][$period] = $available_balance;
}
else
$record['available_balance'][$period] = '';
$sklad_kolichestvo[$tovar_id][$harakteristika_tid][$edinica_izmereniya_tid] = $available_balance;
}
$available_balance = $record['available_balance_start'];
foreach ($record['planed_order_receipts'] as $period => $count) {
if (!$count) {
continue;
}
if (is_numeric($record['leadtime'])) {
$lead_period_number = $period - $record['leadtime'];
if ($lead_period_number <= 0) {
\Drupal::messenger()->addError(t('Part %part. Planned order releases is out of range.', ['%part' => $record['part']]));
$has_error = TRUE;
}
else {
if ($record['lotsize_value']) {
if ($available_balance >= $count) {
$record['available_balance'][$period] = $available_balance - $count;
$available_balance -= $count;
}
else {
$i = 0;
do {
$i++;
$release_value = $record['lotsize_value'] * $i;
} while ($release_value < $count);
$record['planned_order_released'][$lead_period_number] = $release_value;
$record['available_balance'][$period] += $release_value;
$available_balance += $release_value;
$available_balance -= $count;
}
}
else
$record['planned_order_released'][$lead_period_number] = $count;
}
}
else {
$has_error = TRUE;
\Drupal::messenger()->addError(t('Part %part. Lead Time is not specified.', ['%part' => $record['part']]));
}
}
$prev_count = $record['available_balance_start'];
foreach ($record['gross_requirements'] as $period => $count) {
if ($count != '') {
$prev_count = $record['available_balance'][$period];
continue;
}
$record['available_balance'][$period] = $prev_count;
}
if (!$has_error) {
$records[] = $record;
if ($recursive) {
$specificatiya = \Drupal::service('trinion_tp.helper')->getSpecificatsiyaTovara($tovar->id(), $harakteristika_tid, TRUE);
$istochnik_popolneniya = $tovar->get('field_tp_istochnik_popolneniya')->getString();
if ($specificatiya) {
foreach ($specificatiya->get('field_tp_stroki') as $stroka) {
$planned_order_released = $record['planned_order_released'];
$tovar = $stroka->entity->get('field_tp_tovar')->first()->entity;
$product_name = $tovar->get('field_tp_artikul')->getString();
if ($harakteristika = $stroka->entity->get('field_tp_kharakteristika_tovara')->first()) {
$harakteristika = $harakteristika->entity;
$product_name .= ', ' . $harakteristika->label();
}
if (($kolichestvo = $stroka->entity->get('field_tp_kolichestvo')->getString()) > 0) {
foreach ($planned_order_released as $key => $value)
if ($planned_order_released[$key])
$planned_order_released[$key] *= $kolichestvo;
}
$product = [
'tovar' => $tovar,
'unit' => $stroka->entity->get('field_tp_edinica_izmereniya')->getString(),
'harakteristika' => $harakteristika,
'product_name' => $product_name,
'source' => [],
'kolichestvo' => $kolichestvo,
];
$records = $this->generateMrpRecordData($product, $skladi, $records, $planned_order_released, $periods_length, $level + 1, TRUE);
}
}
elseif ($istochnik_popolneniya == 2)
\Drupal::messenger()->addError(t('Part %part. Has no specification.', ['%part' => $record['part']]));
}
}
return $records;
}
public function saveMrpRecordsSubmit(array &$form, FormStateInterface $form_state): void {
$records = $form_state->get('records');
$values = $form_state->getValues();
$mrp_report_data = [];
$i = 0;
$mps = Node::load($values['mps']);
foreach ($records as $record) {
if ($record['level'] == 1) {
$i++;
$mrp_report_data[$i]['source'] = $record['source'];
}
$mrp_report_data[$i]['tables'][] = [
'tovar_id' => $record['tovar']->id(),
'unit' => $record['unit'],
'harakteristika_tid' => $record['harakteristika_tid'],
'level' => $record['level'],
'leadtime' => $record['leadtime'],
'lotsize' => $record['lotsize'],
'kolichestvo' => $record['kolichestvo'],
'part' => $record['part'],
'available_balance_start' => $record['available_balance_start'],
'gross_requirements' => $record['gross_requirements'],
'planed_order_receipts' => $record['planed_order_receipts'],
'available_balance' => $record['available_balance'],
'planned_order_released' => $record['planned_order_released'],
];
}
$uid = \Drupal::currentUser()->id();
foreach ($mrp_report_data as $report) {
foreach ($report['tables'] as $table)
$tables[] = json_encode($table);
$node = Node::create([
'type' => 'zapis_mrp',
'uid' => $uid,
'title' => '',
'status' => 1,
'field_mrp_scenario' => $values['scenario'],
'field_mrp_source_document' => $report['source'],
'field_mrp_table' => $tables,
'field_mrp_period_length_days' => $mps->get('field_mrp_period_length_days')->getString(),
'field_mrp_kolichestvo_periodov' => $mps->get('field_mrp_kolichestvo_periodov')->getString(),
'field_tp_data' => date('Y-m-d\T00:00:00', strtotime($mps->get('field_tp_data')->getString())),
]);
$node->save();
\Drupal::messenger()->addStatus(t('MRP records %num has been created.', ['%num' => $node->label()]));
$pro = new SozdanieZakazaNaProizvodstvo();
$pro->build($node);
$puo = new SozdanieZakazaPostavshiku();
$puo->build($node);
}
}
public static function tableElement($record) {
for ($i = 1; $i <= count($record['gross_requirements']); $i++)
$periods[] = $i;
$rows = [];
foreach ($record['available_balance'] as $key => $val)
if ($val < 0)
$record['available_balance'][$key] = [
'data' => ['#markup' => '<span title="' . $val . '">0</span>'],
];
$rows[] = [['data' => '', 'colspan' => 2], ['data' => t('Periods'), 'colspan' => count($record['gross_requirements'])]];
$rows[] = array_merge([['data' => ['#markup' => "<span title='" . t('Lead Time') . ": {$record['leadtime']}; " . t('Lot Size') . ": {$record['lotsize']}; " . t('Qty per unit') . " {$record['kolichestvo']}'>{$record['part']} " . t('level') . " {$record['level']}</span>"], 'colspan' => 2]], $periods);
$rows[] = array_merge([['data' => t('Gross requirements'), 'colspan' => 2]], $record['gross_requirements']);
$rows[] = array_merge([['data' => t('Scheduled receipts'), 'colspan' => 2]], $record['planed_order_receipts']);
$rows[] = array_merge([t('On hand'), $record['available_balance_start']], $record['available_balance']);
$rows[] = array_merge([['data' => t('Planned-order release'), 'colspan' => 2]], $record['planned_order_released']);
return [
'#theme' => 'table',
'#rows' => $rows,
'#prefix' => '<br>',
'#suffix' => '<br>',
'#attributes' => [
'class' => ['mrp-report-table'],
'data-mrp-report-table' => '1',
],
];
}
}
