beta version

This commit is contained in:
Gloomy 2025-08-11 11:15:22 +00:00
parent cd6821969f
commit ccc3fb3c6f
36 changed files with 3728 additions and 15 deletions

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250806183700 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add warehouseManager field to permission table';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE permission ADD warehouse_manager TINYINT(1) DEFAULT NULL');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('ALTER TABLE permission DROP warehouse_manager');
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250811093832 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
}
}

View file

@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
/**
* Auto-generated Migration: Please modify to your needs!
*/
final class Version20250811101253 extends AbstractMigration
{
public function getDescription(): string
{
return '';
}
public function up(Schema $schema): void
{
// this up() migration is auto-generated, please modify it to your needs
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
}
}

View file

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20250811120010 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add warranty usage columns to plug_warranty_serial table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE plug_warranty_serial ADD used TINYINT(1) DEFAULT NULL');
$this->addSql('ALTER TABLE plug_warranty_serial ADD used_at VARCHAR(50) DEFAULT NULL');
$this->addSql('ALTER TABLE plug_warranty_serial ADD used_ticket_code VARCHAR(255) DEFAULT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE plug_warranty_serial DROP used');
$this->addSql('ALTER TABLE plug_warranty_serial DROP used_at');
$this->addSql('ALTER TABLE plug_warranty_serial DROP used_ticket_code');
}
}

View file

@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20250811123020 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add status and importWorkflowCode to storeroom_ticket';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE storeroom_ticket ADD status VARCHAR(50) DEFAULT NULL');
$this->addSql('ALTER TABLE storeroom_ticket ADD import_workflow_code VARCHAR(255) DEFAULT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE storeroom_ticket DROP status');
$this->addSql('ALTER TABLE storeroom_ticket DROP import_workflow_code');
}
}

View file

@ -0,0 +1,32 @@
<?php
declare(strict_types=1);
namespace DoctrineMigrations;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;
final class Version20250811124530 extends AbstractMigration
{
public function getDescription(): string
{
return 'Add two-step approval flags to permission table';
}
public function up(Schema $schema): void
{
$this->addSql('ALTER TABLE permission ADD require_two_step_sell TINYINT(1) DEFAULT NULL');
$this->addSql('ALTER TABLE permission ADD require_two_step_payment TINYINT(1) DEFAULT NULL');
$this->addSql('ALTER TABLE permission ADD require_two_step_store TINYINT(1) DEFAULT NULL');
}
public function down(Schema $schema): void
{
$this->addSql('ALTER TABLE permission DROP require_two_step_sell');
$this->addSql('ALTER TABLE permission DROP require_two_step_payment');
$this->addSql('ALTER TABLE permission DROP require_two_step_store');
}
}

View file

@ -548,6 +548,8 @@ class BusinessController extends AbstractController
'plugWarranty' => true,
'inquiry' => true,
'ai' => true,
'warehouseManager' => true,
'importWorkflow' => true,
];
} elseif ($perm) {
$result = [
@ -595,7 +597,16 @@ class BusinessController extends AbstractController
'plugWarranty' => $perm->isPlugWarrantyManager(),
'inquiry' => $perm->isInquiry(),
'ai' => $perm->isAi(),
'warehouseManager' => $perm->isWarehouseManager(),
'importWorkflow' => $perm->isImportWorkflow(),
];
if ($perm->isWarehouseManager()) {
$result['commodity'] = true;
$result['store'] = true;
$result['plugWarranty'] = true;
$result['permission'] = true;
}
}
return $this->json($result);
}
@ -668,6 +679,8 @@ class BusinessController extends AbstractController
$perm->setPlugTaxSettings($params['plugTaxSettings']);
$perm->setInquiry($params['inquiry']);
$perm->setAi($params['ai']);
$perm->setWarehouseManager($params['warehouseManager'] ?? false);
$perm->setImportWorkflow($params['importWorkflow'] ?? false);
$entityManager->persist($perm);
$entityManager->flush();
$log->insert('تنظیمات پایه', 'ویرایش دسترسی‌های کاربر با پست الکترونیکی ' . $user->getEmail(), $this->getUser(), $business);

View file

@ -0,0 +1,516 @@
<?php
namespace App\Controller;
use App\Entity\ImportWorkflow;
use App\Entity\ImportWorkflowItem;
use App\Entity\ImportWorkflowPayment;
use App\Entity\ImportWorkflowDocument;
use App\Entity\ImportWorkflowStage;
use App\Entity\ImportWorkflowShipping;
use App\Entity\ImportWorkflowCustoms;
use App\Service\Access;
use App\Service\Log;
use App\Service\Provider;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Security\Http\Attribute\CurrentUser;
use App\Entity\StoreroomTicket;
use App\Entity\Storeroom;
use App\Entity\Person;
use App\Entity\HesabdariDoc;
class ImportWorkflowController extends AbstractController
{
#[Route('/api/import-workflow/list', name: 'api_import_workflow_list', methods: ['GET'])]
public function list(
Request $request,
Access $access,
EntityManagerInterface $entityManager
): JsonResponse {
$acc = $access->hasRole('import_workflow');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$status = $request->query->get('status', '');
$page = (int) $request->query->get('page', 1);
$limit = (int) $request->query->get('limit', 20);
$repository = $entityManager->getRepository(ImportWorkflow::class);
if ($status) {
$workflows = $repository->findByStatus($status, $acc['bid']->getId());
} else {
$workflows = $repository->findByBusiness($acc['bid']->getId());
}
$total = count($workflows);
$offset = ($page - 1) * $limit;
$workflows = array_slice($workflows, $offset, $limit);
$data = [];
foreach ($workflows as $workflow) {
$data[] = [
'id' => $workflow->getId(),
'code' => $workflow->getCode(),
'title' => $workflow->getTitle(),
'status' => $workflow->getStatus(),
'dateSubmit' => $workflow->getDateSubmit(),
'supplierName' => $workflow->getSupplierName(),
'totalAmount' => $workflow->getTotalAmount(),
'currency' => $workflow->getCurrency(),
'submitter' => $workflow->getSubmitter()->getFullName()
];
}
return $this->json([
'Success' => true,
'ErrorCode' => 0,
'ErrorMessage' => '',
'Result' => [
'data' => $data,
'total' => $total,
'page' => $page,
'limit' => $limit
]
]);
}
#[Route('/api/import-workflow/create', name: 'api_import_workflow_create', methods: ['POST'])]
public function create(
Request $request,
Access $access,
Log $log,
Provider $provider,
EntityManagerInterface $entityManager,
#[CurrentUser] $user
): JsonResponse {
$acc = $access->hasRole('import_workflow');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$data = json_decode($request->getContent(), true);
$workflow = new ImportWorkflow();
$workflow->setCode($provider->getAccountingCode($request->headers->get('activeBid'), 'ImportWorkflow'));
$workflow->setTitle($data['title'] ?? '');
$workflow->setBusiness($acc['bid']);
$workflow->setSubmitter($user);
$workflow->setDescription($data['description'] ?? '');
$workflow->setSupplierName($data['supplierName'] ?? '');
$workflow->setSupplierCountry($data['supplierCountry'] ?? '');
$workflow->setSupplierAddress($data['supplierAddress'] ?? '');
$workflow->setSupplierPhone($data['supplierPhone'] ?? '');
$workflow->setSupplierEmail($data['supplierEmail'] ?? '');
$workflow->setTotalAmount($data['totalAmount'] ?? '');
$workflow->setCurrency($data['currency'] ?? '');
$workflow->setExchangeRate($data['exchangeRate'] ?? '');
$workflow->setTotalAmountIRR($data['totalAmountIRR'] ?? '');
$workflow->setStatus('draft');
$entityManager->persist($workflow);
$entityManager->flush();
$log->insert('مدیریت واردات', 'پرونده واردات جدید با کد ' . $workflow->getCode() . ' ایجاد شد.', $user, $request->headers->get('activeBid'));
return $this->json([
'Success' => true,
'ErrorCode' => 0,
'ErrorMessage' => '',
'Result' => [
'id' => $workflow->getId(),
'code' => $workflow->getCode()
]
]);
}
#[Route('/api/import-workflow/stats', name: 'api_import_workflow_stats', methods: ['GET'])]
public function stats(
Request $request,
Access $access,
EntityManagerInterface $entityManager
): JsonResponse {
$acc = $access->hasRole('import_workflow');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$repository = $entityManager->getRepository(ImportWorkflow::class);
$workflows = $repository->findByBusiness($acc['bid']->getId());
$totalWorkflows = count($workflows);
$draftWorkflows = 0;
$processingWorkflows = 0;
$completedWorkflows = 0;
foreach ($workflows as $workflow) {
switch ($workflow->getStatus()) {
case 'draft':
$draftWorkflows++;
break;
case 'processing':
$processingWorkflows++;
break;
case 'completed':
$completedWorkflows++;
break;
}
}
return $this->json([
'Success' => true,
'ErrorCode' => 0,
'ErrorMessage' => '',
'Result' => [
'totalWorkflows' => $totalWorkflows,
'draftWorkflows' => $draftWorkflows,
'processingWorkflows' => $processingWorkflows,
'completedWorkflows' => $completedWorkflows
]
]);
}
#[Route('/api/import-workflow/{id}', name: 'api_import_workflow_get', methods: ['GET'])]
public function get(
string $id,
Request $request,
Access $access,
EntityManagerInterface $entityManager
): JsonResponse {
$acc = $access->hasRole('import_workflow');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$workflowId = (int) $id;
$repository = $entityManager->getRepository(ImportWorkflow::class);
$workflow = $repository->findWithDetails($workflowId, $acc['bid']->getId());
if (!$workflow) {
return $this->json([
'Success' => false,
'ErrorCode' => 404,
'ErrorMessage' => 'پرونده واردات یافت نشد',
'Result' => null
]);
}
$data = [
'id' => $workflow->getId(),
'code' => $workflow->getCode(),
'title' => $workflow->getTitle(),
'status' => $workflow->getStatus(),
'dateSubmit' => $workflow->getDateSubmit(),
'description' => $workflow->getDescription(),
'supplierName' => $workflow->getSupplierName(),
'supplierCountry' => $workflow->getSupplierCountry(),
'supplierAddress' => $workflow->getSupplierAddress(),
'supplierPhone' => $workflow->getSupplierPhone(),
'supplierEmail' => $workflow->getSupplierEmail(),
'totalAmount' => $workflow->getTotalAmount(),
'currency' => $workflow->getCurrency(),
'exchangeRate' => $workflow->getExchangeRate(),
'totalAmountIRR' => $workflow->getTotalAmountIRR(),
'submitter' => $workflow->getSubmitter()->getFullName(),
'items' => [],
'payments' => [],
'documents' => [],
'stages' => [],
'shipping' => [],
'customs' => []
];
foreach ($workflow->getItems() as $item) {
$data['items'][] = [
'id' => $item->getId(),
'name' => $item->getName(),
'productCode' => $item->getProductCode(),
'brand' => $item->getBrand(),
'model' => $item->getModel(),
'originCountry' => $item->getOriginCountry(),
'quantity' => $item->getQuantity(),
'unitPrice' => $item->getUnitPrice(),
'unitPriceIRR' => $item->getUnitPriceIRR(),
'totalPrice' => $item->getTotalPrice(),
'totalPriceIRR' => $item->getTotalPriceIRR(),
'weight' => $item->getWeight(),
'volume' => $item->getVolume(),
'description' => $item->getDescription(),
'specifications' => $item->getSpecifications(),
'dateSubmit' => $item->getDateSubmit()
];
}
foreach ($workflow->getPayments() as $payment) {
$data['payments'][] = [
'id' => $payment->getId(),
'type' => $payment->getType(),
'amount' => $payment->getAmount(),
'currency' => $payment->getCurrency(),
'amountIRR' => $payment->getAmountIRR(),
'paymentDate' => $payment->getPaymentDate(),
'referenceNumber' => $payment->getReferenceNumber(),
'bankName' => $payment->getBankName(),
'accountNumber' => $payment->getAccountNumber(),
'recipientName' => $payment->getRecipientName(),
'status' => $payment->getStatus(),
'description' => $payment->getDescription(),
'receiptNumber' => $payment->getReceiptNumber(),
'dateSubmit' => $payment->getDateSubmit()
];
}
foreach ($workflow->getDocuments() as $document) {
$data['documents'][] = [
'id' => $document->getId(),
'type' => $document->getType(),
'title' => $document->getTitle(),
'filePath' => $document->getFilePath(),
'fileName' => $document->getFileName(),
'fileSize' => $document->getFileSize(),
'fileType' => $document->getFileType(),
'description' => $document->getDescription(),
'documentNumber' => $document->getDocumentNumber(),
'issueDate' => $document->getIssueDate(),
'expiryDate' => $document->getExpiryDate(),
'status' => $document->getStatus(),
'dateSubmit' => $document->getDateSubmit()
];
}
foreach ($workflow->getStages() as $stage) {
$data['stages'][] = [
'id' => $stage->getId(),
'stage' => $stage->getStage(),
'status' => $stage->getStatus(),
'startDate' => $stage->getStartDate(),
'endDate' => $stage->getEndDate(),
'description' => $stage->getDescription(),
'assignedTo' => $stage->getAssignedTo(),
'notes' => $stage->getNotes(),
'dateSubmit' => $stage->getDateSubmit()
];
}
foreach ($workflow->getShipping() as $shipping) {
$data['shipping'][] = [
'id' => $shipping->getId(),
'type' => $shipping->getType(),
'containerNumber' => $shipping->getContainerNumber(),
'billOfLading' => $shipping->getBillOfLading(),
'shippingDate' => $shipping->getShippingDate(),
'arrivalDate' => $shipping->getArrivalDate(),
'unloadingDate' => $shipping->getUnloadingDate(),
'shippingCompany' => $shipping->getShippingCompany(),
'shippingCompanyPhone' => $shipping->getShippingCompanyPhone(),
'shippingCompanyEmail' => $shipping->getShippingCompanyEmail(),
'originPort' => $shipping->getOriginPort(),
'destinationPort' => $shipping->getDestinationPort(),
'vesselName' => $shipping->getVesselName(),
'voyageNumber' => $shipping->getVoyageNumber(),
'description' => $shipping->getDescription(),
'status' => $shipping->getStatus(),
'dateSubmit' => $shipping->getDateSubmit()
];
}
foreach ($workflow->getCustoms() as $customs) {
$data['customs'][] = [
'id' => $customs->getId(),
'declarationNumber' => $customs->getDeclarationNumber(),
'customsCode' => $customs->getCustomsCode(),
'clearanceDate' => $customs->getClearanceDate(),
'customsDuty' => $customs->getCustomsDuty(),
'valueAddedTax' => $customs->getValueAddedTax(),
'otherCharges' => $customs->getOtherCharges(),
'totalCustomsCharges' => $customs->getTotalCustomsCharges(),
'customsBroker' => $customs->getCustomsBroker(),
'customsBrokerPhone' => $customs->getCustomsBrokerPhone(),
'customsBrokerEmail' => $customs->getCustomsBrokerEmail(),
'warehouseNumber' => $customs->getWarehouseNumber(),
'warehouseLocation' => $customs->getWarehouseLocation(),
'description' => $customs->getDescription(),
'status' => $customs->getStatus(),
'dateSubmit' => $customs->getDateSubmit()
];
}
return $this->json([
'Success' => true,
'ErrorCode' => 0,
'ErrorMessage' => '',
'Result' => $data
]);
}
#[Route('/api/import-workflow/{id}/update', name: 'api_import_workflow_update', methods: ['PUT'])]
public function update(
string $id,
Request $request,
Access $access,
Log $log,
EntityManagerInterface $entityManager,
#[CurrentUser] $user
): JsonResponse {
$acc = $access->hasRole('import_workflow');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$workflowId = (int) $id;
$repository = $entityManager->getRepository(ImportWorkflow::class);
$workflow = $repository->find($workflowId);
if (!$workflow || $workflow->getBusiness()->getId() !== $acc['bid']->getId()) {
return $this->json([
'Success' => false,
'ErrorCode' => 404,
'ErrorMessage' => 'پرونده واردات یافت نشد',
'Result' => null
]);
}
$data = json_decode($request->getContent(), true);
if (isset($data['title'])) $workflow->setTitle($data['title']);
if (isset($data['description'])) $workflow->setDescription($data['description']);
if (isset($data['supplierName'])) $workflow->setSupplierName($data['supplierName']);
if (isset($data['supplierCountry'])) $workflow->setSupplierCountry($data['supplierCountry']);
if (isset($data['supplierAddress'])) $workflow->setSupplierAddress($data['supplierAddress']);
if (isset($data['supplierPhone'])) $workflow->setSupplierPhone($data['supplierPhone']);
if (isset($data['supplierEmail'])) $workflow->setSupplierEmail($data['supplierEmail']);
if (isset($data['totalAmount'])) $workflow->setTotalAmount($data['totalAmount']);
if (isset($data['currency'])) $workflow->setCurrency($data['currency']);
if (isset($data['exchangeRate'])) $workflow->setExchangeRate($data['exchangeRate']);
if (isset($data['totalAmountIRR'])) $workflow->setTotalAmountIRR($data['totalAmountIRR']);
if (isset($data['status'])) $workflow->setStatus($data['status']);
$workflow->setDateMod(date('Y-m-d H:i:s'));
$entityManager->flush();
$log->insert('مدیریت واردات', 'پرونده واردات با کد ' . $workflow->getCode() . ' ویرایش شد.', $user, $request->headers->get('activeBid'));
return $this->json([
'Success' => true,
'ErrorCode' => 0,
'ErrorMessage' => '',
'Result' => [
'id' => $workflow->getId(),
'code' => $workflow->getCode()
]
]);
}
#[Route('/api/import-workflow/{id}/delete', name: 'api_import_workflow_delete', methods: ['DELETE'])]
public function delete(
string $id,
Request $request,
Access $access,
Log $log,
EntityManagerInterface $entityManager,
#[CurrentUser] $user
): JsonResponse {
$acc = $access->hasRole('import_workflow');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$workflowId = (int) $id;
$repository = $entityManager->getRepository(ImportWorkflow::class);
$workflow = $repository->find($workflowId);
if (!$workflow || $workflow->getBusiness()->getId() !== $acc['bid']->getId()) {
return $this->json([
'Success' => false,
'ErrorCode' => 404,
'ErrorMessage' => 'پرونده واردات یافت نشد',
'Result' => null
]);
}
$code = $workflow->getCode();
$entityManager->remove($workflow);
$entityManager->flush();
$log->insert('مدیریت واردات', 'پرونده واردات با کد ' . $code . ' حذف شد.', $user, $request->headers->get('activeBid'));
return $this->json([
'Success' => true,
'ErrorCode' => 0,
'ErrorMessage' => '',
'Result' => 'پرونده واردات با موفقیت حذف شد'
]);
}
#[Route('/api/import-workflow/{code}/create-inbound-ticket', name: 'api_import_workflow_create_inbound_ticket', methods: ['POST'])]
public function createInboundTicket(
string $code,
Request $request,
Access $access,
Log $log,
Provider $provider,
EntityManagerInterface $entityManager,
#[CurrentUser] $user
): JsonResponse {
$acc = $access->hasRole('import_workflow');
if (!$acc) {
throw $this->createAccessDeniedException();
}
$params = json_decode($request->getContent() ?: '{}', true);
$storeroomId = $params['storeroom_id'] ?? null;
$personId = $params['person_id'] ?? null;
if (!$storeroomId || !$personId) {
return $this->json(['Success'=>false,'ErrorCode'=>400,'ErrorMessage'=>'پارامترهای ناقص','Result'=>null], 400);
}
$workflow = $entityManager->getRepository(ImportWorkflow::class)->findOneBy(['code'=>$code, 'business'=>$acc['bid']]);
if (!$workflow) {
return $this->json(['Success'=>false,'ErrorCode'=>404,'ErrorMessage'=>'پرونده واردات یافت نشد','Result'=>null], 404);
}
$storeroom = $entityManager->getRepository(Storeroom::class)->find($storeroomId);
$person = $entityManager->getRepository(Person::class)->find($personId);
if (!$storeroom || !$person) {
return $this->json(['Success'=>false,'ErrorCode'=>404,'ErrorMessage'=>'انبار یا طرف حساب یافت نشد','Result'=>null], 404);
}
$ticket = new StoreroomTicket();
$ticket->setSubmitter($user);
$ticket->setDate($workflow->getDateSubmit());
$ticket->setBid($acc['bid']);
$ticket->setDateSubmit((string) time());
$ticket->setDoc(null);
$ticket->setSenderTel(null);
$ticket->setTransfer(null);
$ticket->setYear($acc['year']);
$ticket->setCode($provider->getAccountingCode($acc['bid'], 'storeroom'));
$ticket->setReceiver($person->getNikename());
$ticket->setTransferType($entityManager->getRepository(\App\Entity\StoreroomTransferType::class)->findOneBy([]));
$ticket->setReferral(null);
$ticket->setStoreroom($storeroom);
$ticket->setPerson($person);
$ticket->setType('input');
$ticket->setTypeString('ورود از واردات');
$ticket->setDes('ورود از پرونده واردات #' . $workflow->getCode());
$ticket->setStatus('in_progress');
$ticket->setImportWorkflowCode($workflow->getCode());
$entityManager->persist($ticket);
$entityManager->flush();
$log->insert('مدیریت واردات', 'ایجاد حواله ورود به انبار از پرونده ' . $workflow->getCode(), $user, $acc['bid']);
return $this->json([
'Success'=>true,
'ErrorCode'=>0,
'ErrorMessage'=>'',
'Result'=>[
'ticketCode'=>$ticket->getCode()
]
]);
}
}

View file

@ -479,15 +479,24 @@ class PluginController extends AbstractController
'icon' => ' taxplugin.jpg',
'defaultOn' => null,
],
// [
// 'name' => 'مدیریت گارانتی',
// 'code' => 'warranty',
// 'timestamp' => '32104000',
// 'timelabel' => 'یک سال',
// 'price' => '200000',
// 'icon' => 'warranty.png',
// 'defaultOn' => null,
// ],
[
'name' => 'مدیریت گارانتی',
'code' => 'warranty',
'timestamp' => '32104000',
'timelabel' => 'یک سال',
'price' => '200000',
'icon' => 'warranty.png',
'defaultOn' => null,
],
[
'name' => 'مدیریت واردات کالا',
'code' => 'import-workflow',
'timestamp' => '32104000',
'timelabel' => 'یک سال',
'price' => '200000',
'icon' => 'import-workflow.png',
'defaultOn' => null,
],
];
$repo = $entityManager->getRepository(PluginProdect::class);

View file

@ -9,10 +9,16 @@ use Symfony\Component\HttpFoundation\Request;
use Doctrine\ORM\EntityManagerInterface;
use App\Entity\PlugWarrantySerial;
use App\Entity\Commodity;
use App\Entity\HesabdariDoc;
use App\Service\Access;
use App\Service\Log;
use App\Service\Provider;
use App\Service\Jdate;
use PhpOffice\PhpSpreadsheet\IOFactory;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use App\Service\PluginService;
use App\Service\SMS;
use App\Service\registryMGR;
class PlugWarrantyController extends AbstractController
{
@ -23,6 +29,316 @@ class PlugWarrantyController extends AbstractController
$this->entityManager = $entityManager;
}
#[Route('/api/plugins/warranty/assign/request', name: 'plugin_warranty_assign_request', methods: ['POST'])]
public function plugin_warranty_assign_request(Request $request, EntityManagerInterface $entityManager, Access $access, PluginService $pluginService): JsonResponse
{
try {
$acc = $access->hasRole('plugWarrantyManager');
if(!$acc)
throw $this->createAccessDeniedException();
if (!$pluginService->isActive('warranty', $acc['bid'])) {
return $this->json(['success' => false, 'message' => 'افزونه گارانتی فعال نیست'], 403);
}
$params = json_decode($request->getContent() ?: '{}', true);
// ورودی: commodity_id و count برای هر آیتم حواله
if (!isset($params['items']) || !is_array($params['items'])) {
return $this->json(['error' => 'پارامترهای نامعتبر'], 400);
}
$assignmentCodes = [];
foreach ($params['items'] as $index => $item) {
$commodityId = $item['commodity_id'] ?? null;
$count = (int)($item['count'] ?? 0);
if (!$commodityId || $count <= 0) { continue; }
// تولید کد یکتای تخصیص (تصادفی)
$assignmentCode = bin2hex(random_bytes(10));
$assignmentCodes[] = [
'commodity_id' => $commodityId,
'count' => $count,
'assignmentCode' => $assignmentCode
];
}
return $this->json([
'success' => true,
'codes' => $assignmentCodes
]);
} catch (\Exception $e) {
return $this->json([
'error' => $e->getMessage()
], 500);
}
}
#[Route('/api/plugins/warranty/assign/scan', name: 'plugin_warranty_assign_scan', methods: ['POST'])]
public function plugin_warranty_assign_scan(Request $request, EntityManagerInterface $entityManager, Access $access, PluginService $pluginService): JsonResponse
{
try {
$acc = $access->hasRole('plugWarrantyManager');
if(!$acc)
throw $this->createAccessDeniedException();
if (!$pluginService->isActive('warranty', $acc['bid'])) {
return $this->json(['success' => false, 'message' => 'افزونه گارانتی فعال نیست'], 403);
}
$params = json_decode($request->getContent() ?: '{}', true);
$serialNumber = $params['serialNumber'] ?? null;
$assignmentCode = $params['assignmentCode'] ?? null;
$commodityId = $params['commodity_id'] ?? null; // نوع کالای مورد انتظار
$ticketCode = $params['ticketCode'] ?? null; // اختیاری برای ثبت استفاده
if (!$serialNumber || !$assignmentCode || !$commodityId) {
return $this->json(['success' => false, 'message' => 'پارامترهای ناقص'], 400);
}
$repo = $entityManager->getRepository(PlugWarrantySerial::class);
/** @var PlugWarrantySerial|null $serial */
$serial = $repo->findOneBy([
'serialNumber' => $serialNumber,
'bid' => $acc['bid']
]);
if (!$serial) {
return $this->json(['success' => false, 'message' => 'کد گارانتی یافت نشد']);
}
if ($serial->isUsed()) {
return $this->json(['success' => false, 'message' => 'این سریال قبلاً استفاده شده است']);
}
if (!$serial->getCommodity() || $serial->getCommodity()->getId() !== (int)$commodityId) {
return $this->json(['success' => false, 'message' => 'مغایرت نوع محصول']);
}
// در این نسخه، صرفاً صحت را تایید می‌کنیم و در صورت ارائه ticketCode، وضعیت را مصرف‌شده می‌کنیم
if ($ticketCode) {
$serial->setUsed(true);
$serial->setUsedAt(date('Y-m-d H:i:s'));
$serial->setUsedTicketCode((string)$ticketCode);
$entityManager->persist($serial);
$entityManager->flush();
}
return $this->json(['success' => true, 'message' => 'تأیید شد']);
} catch (\Exception $e) {
return $this->json([
'success' => false,
'message' => $e->getMessage()
], 500);
}
}
#[Route('/api/plugins/warranty/serials/by-invoice/{code}', name: 'plugin_warranty_serials_by_invoice', methods: ['GET'])]
public function plugin_warranty_serials_by_invoice(string $code, Request $request, Access $access, EntityManagerInterface $entityManager, PluginService $pluginService): JsonResponse
{
$acc = $access->hasRole('sell');
if (!$acc) {
throw $this->createAccessDeniedException();
}
if (!$pluginService->isActive('warranty', $acc['bid'])) {
return $this->json(['success' => false, 'message' => 'افزونه گارانتی فعال نیست'], 403);
}
$doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([
'bid' => $acc['bid'],
'code' => $code,
'money' => $acc['money']
]);
if (!$doc) {
return $this->json(['success' => false, 'message' => 'فاکتور یافت نشد'], 404);
}
// سریال‌هایی که در حواله‌های مرتبط با این فاکتور استفاده شده‌اند
$serialRepo = $entityManager->getRepository(PlugWarrantySerial::class);
$serials = $serialRepo->createQueryBuilder('s')
->where('s.bid = :bid')
->andWhere('s.used = true')
->andWhere('s.usedTicketCode IN (
SELECT t.code FROM App\\Entity\\StoreroomTicket t WHERE t.doc = :doc
)')
->setParameter('bid', $acc['bid'])
->setParameter('doc', $doc)
->getQuery()
->getResult();
$result = array_map(function(PlugWarrantySerial $s) {
return [
'serialNumber' => $s->getSerialNumber(),
'commodity' => $s->getCommodity() ? $s->getCommodity()->getName() : null,
'usedAt' => $s->getUsedAt(),
'usedTicketCode' => $s->getUsedTicketCode(),
'status' => $s->isUsed() ? 'used' : 'free'
];
}, $serials);
return $this->json(['success' => true, 'items' => $result]);
}
#[Route('/api/plugins/warranty/send-serials', name: 'plugin_warranty_send_serials', methods: ['POST'])]
public function plugin_warranty_send_serials(Request $request, Access $access, EntityManagerInterface $entityManager, PluginService $pluginService, SMS $SMS, registryMGR $registryMGR): JsonResponse
{
$acc = $access->hasRole('sell');
if (!$acc) {
throw $this->createAccessDeniedException();
}
if (!$pluginService->isActive('warranty', $acc['bid'])) {
return $this->json(['success' => false, 'message' => 'افزونه گارانتی فعال نیست'], 403);
}
$data = json_decode($request->getContent() ?: '{}', true);
$invoiceCode = $data['invoiceCode'] ?? null;
$mobile = $data['mobile'] ?? null;
if (!$invoiceCode || !$mobile) {
return $this->json(['success' => false, 'message' => 'پارامترهای ناقص'], 400);
}
$doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([
'bid' => $acc['bid'],
'code' => $invoiceCode,
'money' => $acc['money']
]);
if (!$doc) {
return $this->json(['success' => false, 'message' => 'فاکتور یافت نشد'], 404);
}
$serialsResponse = $this->plugin_warranty_serials_by_invoice($invoiceCode, $request, $access, $entityManager, $pluginService);
$payload = json_decode($serialsResponse->getContent(), true);
$serials = $payload['items'] ?? [];
if (empty($serials)) {
return $this->json(['success' => false, 'message' => 'سریالی برای ارسال یافت نشد'], 400);
}
$serialNumbers = array_map(fn($s) => $s['serialNumber'], $serials);
$text = 'سریال‌های گارانتی: ' . implode('، ', $serialNumbers);
$SMS->sendByBalance(
[$text],
$registryMGR->get('sms', 'sharefaktor'),
$mobile,
$acc['bid'],
$this->getUser(),
3
);
return $this->json(['success' => true]);
}
#[Route('/api/plugins/warranty/serials/preview-import', name: 'plugin_warranty_serial_preview_import', methods: ['POST'])]
public function plugin_warranty_serial_preview_import(Request $request, Access $access): JsonResponse
{
try {
$acc = $access->hasRole('plugWarrantyManager');
if(!$acc)
throw $this->createAccessDeniedException();
/** @var UploadedFile|null $file */
$file = $request->files->get('file');
if (!$file instanceof UploadedFile) {
return $this->json(['error' => 'فایل ارسال نشده است'], 400);
}
$spreadsheet = IOFactory::load($file->getPathname());
$sheet = $spreadsheet->getActiveSheet();
$rows = $sheet->toArray(null, true, true, true);
$preview = [];
$errors = [];
// انتظار ستون‌های: serialNumber | commodity | description | warrantyStartDate | warrantyEndDate | status
// ردیف اول را عنوان فرض می‌کنیم
$isHeader = true;
foreach ($rows as $rowIndex => $row) {
if ($isHeader) { $isHeader = false; continue; }
$serialNumber = trim((string)($row['A'] ?? ''));
$commodity = trim((string)($row['B'] ?? ''));
$description = trim((string)($row['C'] ?? ''));
$warrantyStartDate = trim((string)($row['D'] ?? ''));
$warrantyEndDate = trim((string)($row['E'] ?? ''));
$status = trim((string)($row['F'] ?? 'active'));
if ($serialNumber === '' || $commodity === '') {
$errors[] = 'ردیف ' . ($rowIndex) . ': شماره سریال یا محصول خالی است';
continue;
}
$preview[] = [
'serialNumber' => $serialNumber,
'commodity' => $commodity,
'description' => $description,
'warrantyStartDate' => $warrantyStartDate,
'warrantyEndDate' => $warrantyEndDate,
'status' => $status ?: 'active'
];
}
return $this->json([
'preview' => $preview,
'errors' => $errors
]);
} catch (\Exception $e) {
return $this->json([
'error' => $e->getMessage()
], 500);
}
}
#[Route('/api/plugins/warranty/serials/import-excel', name: 'plugin_warranty_serial_import_excel', methods: ['POST'])]
public function plugin_warranty_serial_import_excel(Request $request, EntityManagerInterface $entityManager, Access $access): JsonResponse
{
try {
$acc = $access->hasRole('plugWarrantyManager');
if(!$acc)
throw $this->createAccessDeniedException();
/** @var UploadedFile|null $file */
$file = $request->files->get('file');
if (!$file instanceof UploadedFile) {
return $this->json(['error' => 'فایل ارسال نشده است'], 400);
}
$spreadsheet = IOFactory::load($file->getPathname());
$sheet = $spreadsheet->getActiveSheet();
$rows = $sheet->toArray(null, true, true, true);
$serials = [];
$isHeader = true;
foreach ($rows as $row) {
if ($isHeader) { $isHeader = false; continue; }
$serialNumber = trim((string)($row['A'] ?? ''));
$commodity = trim((string)($row['B'] ?? ''));
$description = trim((string)($row['C'] ?? ''));
$warrantyStartDate = trim((string)($row['D'] ?? ''));
$warrantyEndDate = trim((string)($row['E'] ?? ''));
$status = trim((string)($row['F'] ?? 'active'));
if ($serialNumber === '' || $commodity === '') {
continue;
}
// توجه: ستون محصول می‌تواند ID یا CODE یا NAME باشد. اینجا صرفاً پاس‌ترو می‌کنیم و در مرحله نهایی، فرانت با ID نگاشت می‌کند.
$serials[] = [
'serialNumber' => $serialNumber,
'commodity' => $commodity,
'description' => $description,
'warrantyStartDate' => $warrantyStartDate,
'warrantyEndDate' => $warrantyEndDate,
'status' => $status ?: 'active'
];
}
return $this->json([
'serials' => $serials
]);
} catch (\Exception $e) {
return $this->json([
'error' => $e->getMessage()
], 500);
}
}
private function updateExpiredSerials(EntityManagerInterface $entityManager, $businessId): void
{
$repository = $entityManager->getRepository(PlugWarrantySerial::class);

View file

@ -68,6 +68,41 @@ class SellController extends AbstractController
]);
}
#[Route('/api/sell/approve/{code}', name: 'app_sell_approve', methods: ['POST'])]
public function approveSellDoc(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse
{
$acc = $access->hasRole('sell');
if (!$acc) throw $this->createAccessDeniedException();
$doc = $entityManager->getRepository(\App\Entity\HesabdariDoc::class)->findOneBy([
'bid' => $acc['bid'],
'code' => $code,
'money' => $acc['money']
]);
if (!$doc) throw $this->createNotFoundException('فاکتور یافت نشد');
$doc->setStatus('approved');
$entityManager->persist($doc);
$entityManager->flush();
return $this->json(['result' => 0]);
}
#[Route('/api/sell/payment/approve/{code}', name: 'app_sell_payment_approve', methods: ['POST'])]
public function approveSellPayment(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse
{
$acc = $access->hasRole('sell');
if (!$acc) throw $this->createAccessDeniedException();
$paymentDoc = $entityManager->getRepository(\App\Entity\HesabdariDoc::class)->findOneBy([
'bid' => $acc['bid'],
'code' => $code,
'money' => $acc['money'],
'type' => 'sell_receive'
]);
if (!$paymentDoc) throw $this->createNotFoundException('سند دریافت یافت نشد');
$paymentDoc->setStatus('approved');
$entityManager->persist($paymentDoc);
$entityManager->flush();
return $this->json(['result' => 0]);
}
#[Route('/api/sell/get/info/{code}', name: 'app_sell_get_info')]
public function app_sell_get_info(Request $request, Access $access, Log $log, EntityManagerInterface $entityManager, string $code): JsonResponse
{
@ -287,6 +322,13 @@ class SellController extends AbstractController
$hesabdariRow->setPerson($person);
$entityManager->persist($hesabdariRow);
// Two-step approval: اگر پرمیشن کسب‌وکار تأیید دو مرحله‌ای فروش را الزامی کرده باشد
$permission = $entityManager->getRepository(\App\Entity\Permission::class)->findOneBy(['bid' => $acc['bid'], 'user' => $acc['user']]);
if ($permission && $permission->isRequireTwoStepSell()) {
$doc->setStatus('pending_approval');
} else {
$doc->setStatus('approved');
}
$entityManager->persist($doc);
$entityManager->flush();
if (!$doc->getShortlink()) {
@ -778,6 +820,10 @@ class SellController extends AbstractController
$accountStatus['label'] = 'بدهکار';
$accountStatus['value'] = $bd - $bs;
}
// فقط در صورت تایید نهایی مجاز به چاپ هستیم
if ($doc->getStatus() !== 'approved') {
return $this->json(['result' => -10, 'message' => 'فاکتور هنوز تایید نشده است'], 403);
}
if ($params['pdf'] == true || $params['printers'] == true) {
$note = '';
if ($printSettings) {
@ -1272,6 +1318,13 @@ class SellController extends AbstractController
$receiveRow->setPerson($person);
$entityManager->persist($receiveRow);
// Two-step approval برای دریافت/پرداخت
$permission = $entityManager->getRepository(\App\Entity\Permission::class)->findOneBy(['bid' => $acc['bid'], 'user' => $acc['user']]);
if ($permission && $permission->isRequireTwoStepPayment()) {
$paymentDoc->setStatus('pending_approval');
} else {
$paymentDoc->setStatus('approved');
}
$entityManager->persist($paymentDoc);
}
$entityManager->flush();

View file

@ -19,6 +19,8 @@ use App\Service\Log;
use App\Service\PluginService;
use App\Service\registryMGR;
use App\Service\SMS;
use App\Entity\PlugWarrantySerial;
use App\Entity\ArchiveFile;
use Doctrine\ORM\EntityManagerInterface;
use ReflectionException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
@ -54,6 +56,65 @@ class StoreroomController extends AbstractController
);
}
#[Route('/api/storeroom/ticket/attachments/upload/{code}', name: 'app_storeroom_ticket_upload_attachment', methods: ['POST'])]
public function uploadTicketAttachment(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse
{
$acc = $access->hasRole('store');
if (!$acc) throw $this->createAccessDeniedException();
$ticket = $entityManager->getRepository(StoreroomTicket::class)->findOneBy(['bid'=>$acc['bid'],'code'=>$code]);
if (!$ticket) throw $this->createNotFoundException('حواله یافت نشد');
$file = $request->files->get('file');
if (!$file) {
return $this->json(['result'=>-1,'message'=>'فایل ارسال نشده است'], 400);
}
$uploadDir = __DIR__ . '/../../../public_html/uploads/storeroom/';
if (!is_dir($uploadDir)) @mkdir($uploadDir, 0775, true);
$safeName = uniqid('st_', true) . '_' . preg_replace('/[^A-Za-z0-9_\.-]/','_', $file->getClientOriginalName());
$file->move($uploadDir, $safeName);
$archive = new ArchiveFile();
$archive->setBid($acc['bid']);
$archive->setSubmitter($acc['user']);
$archive->setDateSubmit(date('Y-m-d H:i:s'));
$archive->setFilename('/uploads/storeroom/' . $safeName);
$archive->setCat('storeroom_ticket');
$archive->setFileType($file->getClientMimeType() ?: 'application/octet-stream');
$archive->setPublic(false);
$archive->setDes($request->request->get('des'));
$archive->setRelatedDocType('storeroom_ticket');
$archive->setRelatedDocCode($ticket->getCode());
$archive->setFileSize((string) $file->getSize());
$entityManager->persist($archive);
$entityManager->flush();
return $this->json(['result'=>0]);
}
#[Route('/api/storeroom/ticket/attachments/{code}', name: 'app_storeroom_ticket_list_attachments', methods: ['GET'])]
public function listTicketAttachments(string $code, Access $access, EntityManagerInterface $entityManager): JsonResponse
{
$acc = $access->hasRole('store');
if (!$acc) throw $this->createAccessDeniedException();
$ticket = $entityManager->getRepository(StoreroomTicket::class)->findOneBy(['bid'=>$acc['bid'],'code'=>$code]);
if (!$ticket) throw $this->createNotFoundException('حواله یافت نشد');
$items = $entityManager->getRepository(ArchiveFile::class)->findBy([
'bid'=>$acc['bid'],
'relatedDocType'=>'storeroom_ticket',
'relatedDocCode'=>$ticket->getCode()
], ['id'=>'DESC']);
return $this->json(array_map(function(ArchiveFile $a){
return [
'id'=>$a->getId(),
'filename'=>$a->getFilename(),
'fileType'=>$a->getFileType(),
'fileSize'=>$a->getFileSize(),
'des'=>$a->getDes(),
'dateSubmit'=>$a->getDateSubmit(),
];
}, $items));
}
#[Route('/api/storeroom/mod/{code}', name: 'app_storeroom_mod')]
public function app_storeroom_mod(Provider $provider, Request $request, Access $access, Log $log, EntityManagerInterface $entityManager, $code = 0): JsonResponse
{
@ -411,6 +472,12 @@ class StoreroomController extends AbstractController
$ticket->setType($params['ticket']['type']);
$ticket->setTypeString($params['ticket']['typeString']);
$ticket->setDes($params['ticket']['des']);
// وضعیت اولیه
$ticket->setStatus('in_progress');
// اگر از پرونده واردات آمده
if (array_key_exists('importWorkflowCode', $params['ticket'])) {
$ticket->setImportWorkflowCode($params['ticket']['importWorkflowCode']);
}
$entityManager->persist($ticket);
//$entityManager->flush();
@ -418,6 +485,41 @@ class StoreroomController extends AbstractController
$docRows = $entityManager->getRepository(HesabdariRow::class)->findBy([
'doc' => $doc
]);
// بررسی الزام سریال: اگر در بدنه درخواست گزینه requireWarrantySerial=true باشد، قبل از ثبت نهایی، کف سریال‌های آزاد کالا را چک می‌کنیم
$requireWarrantySerial = isset($params['ticket']['requireWarrantySerial']) && $params['ticket']['requireWarrantySerial'] === true;
if ($requireWarrantySerial) {
if (!$pluginService->isActive('warranty', $acc['bid'])) {
return $this->json([
'result' => -5,
'message' => 'افزونه گارانتی فعال نیست'
], 403);
}
}
if ($requireWarrantySerial) {
foreach ($params['items'] as $item) {
$row = $entityManager->getRepository(HesabdariRow::class)->findOneBy([
'bid' => $acc['bid'],
'doc' => $doc,
'id' => $item['id'],
]);
if (!$row || !$row->getCommodity())
throw $this->createNotFoundException('کالا یافت نشد!');
$commodity = $row->getCommodity();
$freeSerialCount = $entityManager->getRepository(PlugWarrantySerial::class)->count([
'bid' => $acc['bid'],
'commodity' => $commodity,
'used' => null,
'status' => 'active'
]);
if ($freeSerialCount < (int)$item['ticketCount']) {
return $this->json([
'result' => -2,
'message' => 'تعداد سریال گارانتی آزاد برای کالا کافی نیست'
], 400);
}
}
}
foreach ($params['items'] as $item) {
$row = $entityManager->getRepository(HesabdariRow::class)->findOneBy([
'bid' => $acc['bid'],
@ -441,8 +543,44 @@ class StoreroomController extends AbstractController
$ticketItem->setCommodity($row->getCommodity());
$ticketItem->setType($item['type']);
$entityManager->persist($ticketItem);
// اگر الزام سریال فعال است و سریال‌ها هم در همین درخواست آمده‌اند، آن‌ها را مصرف کنیم
if ($requireWarrantySerial && isset($item['warrantySerials']) && is_array($item['warrantySerials'])) {
$serials = $item['warrantySerials'];
if (count($serials) != (int)$item['ticketCount']) {
return $this->json([
'result' => -3,
'message' => 'تعداد سریال‌های ارسالی با تعداد حواله همخوانی ندارد'
], 400);
}
foreach ($serials as $serialNumber) {
/** @var PlugWarrantySerial|null $serial */
$serial = $entityManager->getRepository(PlugWarrantySerial::class)->findOneBy([
'bid' => $acc['bid'],
'serialNumber' => $serialNumber,
'commodity' => $row->getCommodity(),
'status' => 'active'
]);
if (!$serial || $serial->isUsed()) {
return $this->json([
'result' => -4,
'message' => 'سریال نامعتبر یا قبلاً مصرف شده: ' . $serialNumber
], 400);
}
$serial->setUsed(true);
$serial->setUsedAt(date('Y-m-d H:i:s'));
$serial->setUsedTicketCode($ticket->getCode());
$entityManager->persist($serial);
}
}
}
$entityManager->flush();
// اگر تأیید دو مرحله‌ای حواله فعال باشد، وضعیت را pending_approval بگذاریم
$permission = $entityManager->getRepository(\App\Entity\Permission::class)->findOneBy(['bid' => $acc['bid'], 'user' => $acc['user']]);
if ($permission && $permission->isRequireTwoStepStore()) {
$ticket->setStatus('pending_approval');
$entityManager->persist($ticket);
$entityManager->flush();
}
//save logs
$log->insert('انبارداری', 'حواله انبار با شماره ' . $ticket->getCode() . ' اضافه / ویرایش شد.', $this->getUser(), $acc['bid']);
if ($pluginService->isActive('accpro', $acc['bid'])) {
@ -503,6 +641,59 @@ class StoreroomController extends AbstractController
]);
}
#[Route('/api/storeroom/ticket/status/{code}', name: 'app_storeroom_ticket_status_update', methods: ['POST'])]
public function app_storeroom_ticket_status_update(string $code, Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse
{
$acc = $access->hasRole('store');
if (!$acc)
throw $this->createAccessDeniedException();
$params = json_decode($request->getContent() ?: '{}', true);
$status = $params['status'] ?? null; // in_progress|done|rejected|approved|pending_approval
if (!in_array($status, ['in_progress','done','rejected','approved','pending_approval'])) {
return $this->json(['result' => -1, 'message' => 'وضعیت نامعتبر'], 400);
}
$ticket = $entityManager->getRepository(StoreroomTicket::class)->findOneBy([
'bid' => $acc['bid'],
'code' => $code
]);
if (!$ticket) {
throw $this->createNotFoundException('حواله یافت نشد.');
}
$ticket->setStatus($status);
$entityManager->persist($ticket);
$entityManager->flush();
return $this->json(['result' => 0]);
}
#[Route('/api/storeroom/tickets', name: 'app_storeroom_tickets_by_status', methods: ['GET'])]
public function app_storeroom_tickets_by_status(Request $request, Access $access, EntityManagerInterface $entityManager): JsonResponse
{
$acc = $access->hasRole('store');
if (!$acc)
throw $this->createAccessDeniedException();
$status = $request->query->get('status');
$criteria = [
'bid' => $acc['bid'],
'year' => $acc['year'],
];
if ($status) {
$criteria['status'] = $status;
}
$tickets = $entityManager->getRepository(StoreroomTicket::class)->findBy($criteria, ['date' => 'DESC']);
return $this->json(array_map(function(StoreroomTicket $t){
return [
'code' => $t->getCode(),
'date' => $t->getDate(),
'type' => $t->getType(),
'typeString' => $t->getTypeString(),
'status' => $t->getStatus(),
'importWorkflowCode' => $t->getImportWorkflowCode(),
'person' => $t->getPerson() ? $t->getPerson()->getNikename() : null,
'storeroom' => $t->getStoreroom() ? $t->getStoreroom()->getName() : null,
];
}, $tickets));
}
#[Route('/api/storeroom/tickets/list/{type}', name: 'app_storeroom_tickets_list')]
public function app_storeroom_tickets_list(string $type, Provider $provider, Request $request, Access $access, Log $log, EntityManagerInterface $entityManager): JsonResponse
{
@ -659,6 +850,13 @@ class StoreroomController extends AbstractController
} else {
$title = 'حواله خروج از انبار';
}
// جلوگیری از چاپ پیش از تایید در صورت نیاز
$permission = $entityManager->getRepository(\App\Entity\Permission::class)->findOneBy(['bid' => $acc['bid'], 'user' => $acc['user']]);
if ($permission && $permission->isRequireTwoStepStore()) {
if ($doc->getStatus() !== 'approved' && $doc->getStatus() !== 'done') {
return $this->json(['result' => -10, 'message' => 'حواله هنوز تایید نشده است'], 403);
}
}
$pdfPid = 0;
$pdfPid = $provider->createPrint(
$acc['bid'],

View file

@ -117,6 +117,9 @@ class Business
#[ORM\Column(length: 255, nullable: true)]
private ?string $cashdeskCode = '1000';
#[ORM\Column(type: Types::BIGINT, nullable: true)]
private ?string $importWorkflowCode = null;
#[ORM\OneToMany(mappedBy: 'bid', targetEntity: Salary::class, orphanRemoval: true)]
private Collection $salaries;
@ -307,6 +310,9 @@ class Business
#[Ignore]
private Collection $plugWarrantySerials;
#[ORM\OneToMany(mappedBy: 'business', targetEntity: ImportWorkflow::class, orphanRemoval: true)]
private Collection $importWorkflows;
public function __construct()
{
$this->logs = new ArrayCollection();
@ -352,6 +358,7 @@ class Business
$this->plugHrmDocs = new ArrayCollection();
$this->aiConversations = new ArrayCollection();
$this->plugWarrantySerials = new ArrayCollection();
$this->importWorkflows = new ArrayCollection();
}
public function getId(): ?int
@ -879,6 +886,18 @@ class Business
return $this;
}
public function getImportWorkflowCode(): ?string
{
return $this->importWorkflowCode;
}
public function setImportWorkflowCode(?string $importWorkflowCode): self
{
$this->importWorkflowCode = $importWorkflowCode;
return $this;
}
/**
* @return Collection<int, Salary>
*/
@ -2155,4 +2174,28 @@ class Business
return $this;
}
public function getImportWorkflows(): Collection
{
return $this->importWorkflows;
}
public function addImportWorkflow(ImportWorkflow $importWorkflow): static
{
if (!$this->importWorkflows->contains($importWorkflow)) {
$this->importWorkflows->add($importWorkflow);
$importWorkflow->setBusiness($this);
}
return $this;
}
public function removeImportWorkflow(ImportWorkflow $importWorkflow): static
{
if ($this->importWorkflows->removeElement($importWorkflow)) {
if ($importWorkflow->getBusiness() === $this) {
$importWorkflow->setBusiness(null);
}
}
return $this;
}
}

View file

@ -0,0 +1,441 @@
<?php
namespace App\Entity;
use App\Repository\ImportWorkflowRepository;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;
#[ORM\Entity(repositoryClass: ImportWorkflowRepository::class)]
class ImportWorkflow
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\Column(length: 255, unique: true)]
private ?string $code = null;
#[ORM\Column(length: 255)]
private ?string $title = null;
#[ORM\ManyToOne(inversedBy: 'importWorkflows')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?Business $business = null;
#[ORM\ManyToOne(inversedBy: 'importWorkflows')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?User $submitter = null;
#[ORM\Column(length: 255)]
private ?string $dateSubmit = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $dateMod = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $status = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $supplierName = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $supplierCountry = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $supplierAddress = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $supplierPhone = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $supplierEmail = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $totalAmount = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $currency = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $exchangeRate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $totalAmountIRR = null;
#[ORM\OneToMany(mappedBy: 'importWorkflow', targetEntity: ImportWorkflowItem::class, orphanRemoval: true)]
private Collection $items;
#[ORM\OneToMany(mappedBy: 'importWorkflow', targetEntity: ImportWorkflowPayment::class, orphanRemoval: true)]
private Collection $payments;
#[ORM\OneToMany(mappedBy: 'importWorkflow', targetEntity: ImportWorkflowDocument::class, orphanRemoval: true)]
private Collection $documents;
#[ORM\OneToMany(mappedBy: 'importWorkflow', targetEntity: ImportWorkflowStage::class, orphanRemoval: true)]
private Collection $stages;
#[ORM\OneToMany(mappedBy: 'importWorkflow', targetEntity: ImportWorkflowShipping::class, orphanRemoval: true)]
private Collection $shipping;
#[ORM\OneToMany(mappedBy: 'importWorkflow', targetEntity: ImportWorkflowCustoms::class, orphanRemoval: true)]
private Collection $customs;
public function __construct()
{
$this->items = new ArrayCollection();
$this->payments = new ArrayCollection();
$this->documents = new ArrayCollection();
$this->stages = new ArrayCollection();
$this->shipping = new ArrayCollection();
$this->customs = new ArrayCollection();
$this->dateSubmit = date('Y-m-d H:i:s');
$this->status = 'draft';
}
public function getId(): ?int
{
return $this->id;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): static
{
$this->code = $code;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getBusiness(): ?Business
{
return $this->business;
}
public function setBusiness(?Business $business): static
{
$this->business = $business;
return $this;
}
public function getSubmitter(): ?User
{
return $this->submitter;
}
public function setSubmitter(?User $submitter): static
{
$this->submitter = $submitter;
return $this;
}
public function getDateSubmit(): ?string
{
return $this->dateSubmit;
}
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
public function getDateMod(): ?string
{
return $this->dateMod;
}
public function setDateMod(?string $dateMod): static
{
$this->dateMod = $dateMod;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getSupplierName(): ?string
{
return $this->supplierName;
}
public function setSupplierName(?string $supplierName): static
{
$this->supplierName = $supplierName;
return $this;
}
public function getSupplierCountry(): ?string
{
return $this->supplierCountry;
}
public function setSupplierCountry(?string $supplierCountry): static
{
$this->supplierCountry = $supplierCountry;
return $this;
}
public function getSupplierAddress(): ?string
{
return $this->supplierAddress;
}
public function setSupplierAddress(?string $supplierAddress): static
{
$this->supplierAddress = $supplierAddress;
return $this;
}
public function getSupplierPhone(): ?string
{
return $this->supplierPhone;
}
public function setSupplierPhone(?string $supplierPhone): static
{
$this->supplierPhone = $supplierPhone;
return $this;
}
public function getSupplierEmail(): ?string
{
return $this->supplierEmail;
}
public function setSupplierEmail(?string $supplierEmail): static
{
$this->supplierEmail = $supplierEmail;
return $this;
}
public function getTotalAmount(): ?string
{
return $this->totalAmount;
}
public function setTotalAmount(?string $totalAmount): static
{
$this->totalAmount = $totalAmount;
return $this;
}
public function getCurrency(): ?string
{
return $this->currency;
}
public function setCurrency(?string $currency): static
{
$this->currency = $currency;
return $this;
}
public function getExchangeRate(): ?string
{
return $this->exchangeRate;
}
public function setExchangeRate(?string $exchangeRate): static
{
$this->exchangeRate = $exchangeRate;
return $this;
}
public function getTotalAmountIRR(): ?string
{
return $this->totalAmountIRR;
}
public function setTotalAmountIRR(?string $totalAmountIRR): static
{
$this->totalAmountIRR = $totalAmountIRR;
return $this;
}
public function getItems(): Collection
{
return $this->items;
}
public function addItem(ImportWorkflowItem $item): static
{
if (!$this->items->contains($item)) {
$this->items->add($item);
$item->setImportWorkflow($this);
}
return $this;
}
public function removeItem(ImportWorkflowItem $item): static
{
if ($this->items->removeElement($item)) {
if ($item->getImportWorkflow() === $this) {
$item->setImportWorkflow(null);
}
}
return $this;
}
public function getPayments(): Collection
{
return $this->payments;
}
public function addPayment(ImportWorkflowPayment $payment): static
{
if (!$this->payments->contains($payment)) {
$this->payments->add($payment);
$payment->setImportWorkflow($this);
}
return $this;
}
public function removePayment(ImportWorkflowPayment $payment): static
{
if ($this->payments->removeElement($payment)) {
if ($payment->getImportWorkflow() === $this) {
$payment->setImportWorkflow(null);
}
}
return $this;
}
public function getDocuments(): Collection
{
return $this->documents;
}
public function addDocument(ImportWorkflowDocument $document): static
{
if (!$this->documents->contains($document)) {
$this->documents->add($document);
$document->setImportWorkflow($this);
}
return $this;
}
public function removeDocument(ImportWorkflowDocument $document): static
{
if ($this->documents->removeElement($document)) {
if ($document->getImportWorkflow() === $this) {
$document->setImportWorkflow(null);
}
}
return $this;
}
public function getStages(): Collection
{
return $this->stages;
}
public function addStage(ImportWorkflowStage $stage): static
{
if (!$this->stages->contains($stage)) {
$this->stages->add($stage);
$stage->setImportWorkflow($this);
}
return $this;
}
public function removeStage(ImportWorkflowStage $stage): static
{
if ($this->stages->removeElement($stage)) {
if ($stage->getImportWorkflow() === $this) {
$stage->setImportWorkflow(null);
}
}
return $this;
}
public function getShipping(): Collection
{
return $this->shipping;
}
public function addShipping(ImportWorkflowShipping $shipping): static
{
if (!$this->shipping->contains($shipping)) {
$this->shipping->add($shipping);
$shipping->setImportWorkflow($this);
}
return $this;
}
public function removeShipping(ImportWorkflowShipping $shipping): static
{
if ($this->shipping->removeElement($shipping)) {
if ($shipping->getImportWorkflow() === $this) {
$shipping->setImportWorkflow(null);
}
}
return $this;
}
public function getCustoms(): Collection
{
return $this->customs;
}
public function addCustom(ImportWorkflowCustoms $custom): static
{
if (!$this->customs->contains($custom)) {
$this->customs->add($custom);
$custom->setImportWorkflow($this);
}
return $this;
}
public function removeCustom(ImportWorkflowCustoms $custom): static
{
if ($this->customs->removeElement($custom)) {
if ($custom->getImportWorkflow() === $this) {
$custom->setImportWorkflow(null);
}
}
return $this;
}
}

View file

@ -0,0 +1,254 @@
<?php
namespace App\Entity;
use App\Repository\ImportWorkflowCustomsRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;
#[ORM\Entity(repositoryClass: ImportWorkflowCustomsRepository::class)]
class ImportWorkflowCustoms
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'customs')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?ImportWorkflow $importWorkflow = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $declarationNumber = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $customsCode = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $clearanceDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $customsDuty = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $valueAddedTax = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $otherCharges = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $totalCustomsCharges = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $customsBroker = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $customsBrokerPhone = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $customsBrokerEmail = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $warehouseNumber = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $warehouseLocation = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255)]
private ?string $dateSubmit = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $status = null;
public function __construct()
{
$this->dateSubmit = date('Y-m-d H:i:s');
$this->status = 'pending';
}
public function getId(): ?int
{
return $this->id;
}
public function getImportWorkflow(): ?ImportWorkflow
{
return $this->importWorkflow;
}
public function setImportWorkflow(?ImportWorkflow $importWorkflow): static
{
$this->importWorkflow = $importWorkflow;
return $this;
}
public function getDeclarationNumber(): ?string
{
return $this->declarationNumber;
}
public function setDeclarationNumber(?string $declarationNumber): static
{
$this->declarationNumber = $declarationNumber;
return $this;
}
public function getCustomsCode(): ?string
{
return $this->customsCode;
}
public function setCustomsCode(?string $customsCode): static
{
$this->customsCode = $customsCode;
return $this;
}
public function getClearanceDate(): ?string
{
return $this->clearanceDate;
}
public function setClearanceDate(?string $clearanceDate): static
{
$this->clearanceDate = $clearanceDate;
return $this;
}
public function getCustomsDuty(): ?string
{
return $this->customsDuty;
}
public function setCustomsDuty(?string $customsDuty): static
{
$this->customsDuty = $customsDuty;
return $this;
}
public function getValueAddedTax(): ?string
{
return $this->valueAddedTax;
}
public function setValueAddedTax(?string $valueAddedTax): static
{
$this->valueAddedTax = $valueAddedTax;
return $this;
}
public function getOtherCharges(): ?string
{
return $this->otherCharges;
}
public function setOtherCharges(?string $otherCharges): static
{
$this->otherCharges = $otherCharges;
return $this;
}
public function getTotalCustomsCharges(): ?string
{
return $this->totalCustomsCharges;
}
public function setTotalCustomsCharges(?string $totalCustomsCharges): static
{
$this->totalCustomsCharges = $totalCustomsCharges;
return $this;
}
public function getCustomsBroker(): ?string
{
return $this->customsBroker;
}
public function setCustomsBroker(?string $customsBroker): static
{
$this->customsBroker = $customsBroker;
return $this;
}
public function getCustomsBrokerPhone(): ?string
{
return $this->customsBrokerPhone;
}
public function setCustomsBrokerPhone(?string $customsBrokerPhone): static
{
$this->customsBrokerPhone = $customsBrokerPhone;
return $this;
}
public function getCustomsBrokerEmail(): ?string
{
return $this->customsBrokerEmail;
}
public function setCustomsBrokerEmail(?string $customsBrokerEmail): static
{
$this->customsBrokerEmail = $customsBrokerEmail;
return $this;
}
public function getWarehouseNumber(): ?string
{
return $this->warehouseNumber;
}
public function setWarehouseNumber(?string $warehouseNumber): static
{
$this->warehouseNumber = $warehouseNumber;
return $this;
}
public function getWarehouseLocation(): ?string
{
return $this->warehouseLocation;
}
public function setWarehouseLocation(?string $warehouseLocation): static
{
$this->warehouseLocation = $warehouseLocation;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getDateSubmit(): ?string
{
return $this->dateSubmit;
}
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
}

View file

@ -0,0 +1,213 @@
<?php
namespace App\Entity;
use App\Repository\ImportWorkflowDocumentRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;
#[ORM\Entity(repositoryClass: ImportWorkflowDocumentRepository::class)]
class ImportWorkflowDocument
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'documents')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?ImportWorkflow $importWorkflow = null;
#[ORM\Column(length: 255)]
private ?string $type = null;
#[ORM\Column(length: 255)]
private ?string $title = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $filePath = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $fileName = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $fileSize = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $fileType = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255)]
private ?string $dateSubmit = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $documentNumber = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $issueDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $expiryDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $status = null;
public function __construct()
{
$this->dateSubmit = date('Y-m-d H:i:s');
$this->status = 'active';
}
public function getId(): ?int
{
return $this->id;
}
public function getImportWorkflow(): ?ImportWorkflow
{
return $this->importWorkflow;
}
public function setImportWorkflow(?ImportWorkflow $importWorkflow): static
{
$this->importWorkflow = $importWorkflow;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): static
{
$this->type = $type;
return $this;
}
public function getTitle(): ?string
{
return $this->title;
}
public function setTitle(string $title): static
{
$this->title = $title;
return $this;
}
public function getFilePath(): ?string
{
return $this->filePath;
}
public function setFilePath(?string $filePath): static
{
$this->filePath = $filePath;
return $this;
}
public function getFileName(): ?string
{
return $this->fileName;
}
public function setFileName(?string $fileName): static
{
$this->fileName = $fileName;
return $this;
}
public function getFileSize(): ?string
{
return $this->fileSize;
}
public function setFileSize(?string $fileSize): static
{
$this->fileSize = $fileSize;
return $this;
}
public function getFileType(): ?string
{
return $this->fileType;
}
public function setFileType(?string $fileType): static
{
$this->fileType = $fileType;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getDateSubmit(): ?string
{
return $this->dateSubmit;
}
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
public function getDocumentNumber(): ?string
{
return $this->documentNumber;
}
public function setDocumentNumber(?string $documentNumber): static
{
$this->documentNumber = $documentNumber;
return $this;
}
public function getIssueDate(): ?string
{
return $this->issueDate;
}
public function setIssueDate(?string $issueDate): static
{
$this->issueDate = $issueDate;
return $this;
}
public function getExpiryDate(): ?string
{
return $this->expiryDate;
}
public function setExpiryDate(?string $expiryDate): static
{
$this->expiryDate = $expiryDate;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
}

View file

@ -0,0 +1,254 @@
<?php
namespace App\Entity;
use App\Repository\ImportWorkflowItemRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;
#[ORM\Entity(repositoryClass: ImportWorkflowItemRepository::class)]
class ImportWorkflowItem
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'items')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?ImportWorkflow $importWorkflow = null;
#[ORM\Column(length: 255)]
private ?string $name = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $productCode = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $brand = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $model = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $originCountry = null;
#[ORM\Column(length: 255)]
private ?string $quantity = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $unitPrice = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $unitPriceIRR = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $totalPrice = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $totalPriceIRR = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $weight = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $volume = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $specifications = null;
#[ORM\Column(length: 255)]
private ?string $dateSubmit = null;
public function __construct()
{
$this->dateSubmit = date('Y-m-d H:i:s');
}
public function getId(): ?int
{
return $this->id;
}
public function getImportWorkflow(): ?ImportWorkflow
{
return $this->importWorkflow;
}
public function setImportWorkflow(?ImportWorkflow $importWorkflow): static
{
$this->importWorkflow = $importWorkflow;
return $this;
}
public function getName(): ?string
{
return $this->name;
}
public function setName(string $name): static
{
$this->name = $name;
return $this;
}
public function getProductCode(): ?string
{
return $this->productCode;
}
public function setProductCode(?string $productCode): static
{
$this->productCode = $productCode;
return $this;
}
public function getBrand(): ?string
{
return $this->brand;
}
public function setBrand(?string $brand): static
{
$this->brand = $brand;
return $this;
}
public function getModel(): ?string
{
return $this->model;
}
public function setModel(?string $model): static
{
$this->model = $model;
return $this;
}
public function getOriginCountry(): ?string
{
return $this->originCountry;
}
public function setOriginCountry(?string $originCountry): static
{
$this->originCountry = $originCountry;
return $this;
}
public function getQuantity(): ?string
{
return $this->quantity;
}
public function setQuantity(string $quantity): static
{
$this->quantity = $quantity;
return $this;
}
public function getUnitPrice(): ?string
{
return $this->unitPrice;
}
public function setUnitPrice(?string $unitPrice): static
{
$this->unitPrice = $unitPrice;
return $this;
}
public function getUnitPriceIRR(): ?string
{
return $this->unitPriceIRR;
}
public function setUnitPriceIRR(?string $unitPriceIRR): static
{
$this->unitPriceIRR = $unitPriceIRR;
return $this;
}
public function getTotalPrice(): ?string
{
return $this->totalPrice;
}
public function setTotalPrice(?string $totalPrice): static
{
$this->totalPrice = $totalPrice;
return $this;
}
public function getTotalPriceIRR(): ?string
{
return $this->totalPriceIRR;
}
public function setTotalPriceIRR(?string $totalPriceIRR): static
{
$this->totalPriceIRR = $totalPriceIRR;
return $this;
}
public function getWeight(): ?string
{
return $this->weight;
}
public function setWeight(?string $weight): static
{
$this->weight = $weight;
return $this;
}
public function getVolume(): ?string
{
return $this->volume;
}
public function setVolume(?string $volume): static
{
$this->volume = $volume;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getSpecifications(): ?string
{
return $this->specifications;
}
public function setSpecifications(?string $specifications): static
{
$this->specifications = $specifications;
return $this;
}
public function getDateSubmit(): ?string
{
return $this->dateSubmit;
}
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
}

View file

@ -0,0 +1,227 @@
<?php
namespace App\Entity;
use App\Repository\ImportWorkflowPaymentRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;
#[ORM\Entity(repositoryClass: ImportWorkflowPaymentRepository::class)]
class ImportWorkflowPayment
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'payments')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?ImportWorkflow $importWorkflow = null;
#[ORM\Column(length: 255)]
private ?string $type = null;
#[ORM\Column(length: 255)]
private ?string $amount = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $currency = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $amountIRR = null;
#[ORM\Column(length: 255)]
private ?string $paymentDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $referenceNumber = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $bankName = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $accountNumber = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $recipientName = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $status = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $receiptNumber = null;
#[ORM\Column(length: 255)]
private ?string $dateSubmit = null;
public function __construct()
{
$this->dateSubmit = date('Y-m-d H:i:s');
$this->status = 'pending';
}
public function getId(): ?int
{
return $this->id;
}
public function getImportWorkflow(): ?ImportWorkflow
{
return $this->importWorkflow;
}
public function setImportWorkflow(?ImportWorkflow $importWorkflow): static
{
$this->importWorkflow = $importWorkflow;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): static
{
$this->type = $type;
return $this;
}
public function getAmount(): ?string
{
return $this->amount;
}
public function setAmount(string $amount): static
{
$this->amount = $amount;
return $this;
}
public function getCurrency(): ?string
{
return $this->currency;
}
public function setCurrency(?string $currency): static
{
$this->currency = $currency;
return $this;
}
public function getAmountIRR(): ?string
{
return $this->amountIRR;
}
public function setAmountIRR(?string $amountIRR): static
{
$this->amountIRR = $amountIRR;
return $this;
}
public function getPaymentDate(): ?string
{
return $this->paymentDate;
}
public function setPaymentDate(string $paymentDate): static
{
$this->paymentDate = $paymentDate;
return $this;
}
public function getReferenceNumber(): ?string
{
return $this->referenceNumber;
}
public function setReferenceNumber(?string $referenceNumber): static
{
$this->referenceNumber = $referenceNumber;
return $this;
}
public function getBankName(): ?string
{
return $this->bankName;
}
public function setBankName(?string $bankName): static
{
$this->bankName = $bankName;
return $this;
}
public function getAccountNumber(): ?string
{
return $this->accountNumber;
}
public function setAccountNumber(?string $accountNumber): static
{
$this->accountNumber = $accountNumber;
return $this;
}
public function getRecipientName(): ?string
{
return $this->recipientName;
}
public function setRecipientName(?string $recipientName): static
{
$this->recipientName = $recipientName;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getReceiptNumber(): ?string
{
return $this->receiptNumber;
}
public function setReceiptNumber(?string $receiptNumber): static
{
$this->receiptNumber = $receiptNumber;
return $this;
}
public function getDateSubmit(): ?string
{
return $this->dateSubmit;
}
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
}

View file

@ -0,0 +1,269 @@
<?php
namespace App\Entity;
use App\Repository\ImportWorkflowShippingRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;
#[ORM\Entity(repositoryClass: ImportWorkflowShippingRepository::class)]
class ImportWorkflowShipping
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'shipping')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?ImportWorkflow $importWorkflow = null;
#[ORM\Column(length: 255)]
private ?string $type = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $containerNumber = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $billOfLading = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $shippingDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $arrivalDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $unloadingDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $shippingCompany = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $shippingCompanyPhone = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $shippingCompanyEmail = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $originPort = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $destinationPort = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $vesselName = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $voyageNumber = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255)]
private ?string $dateSubmit = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $status = null;
public function __construct()
{
$this->dateSubmit = date('Y-m-d H:i:s');
$this->status = 'pending';
}
public function getId(): ?int
{
return $this->id;
}
public function getImportWorkflow(): ?ImportWorkflow
{
return $this->importWorkflow;
}
public function setImportWorkflow(?ImportWorkflow $importWorkflow): static
{
$this->importWorkflow = $importWorkflow;
return $this;
}
public function getType(): ?string
{
return $this->type;
}
public function setType(string $type): static
{
$this->type = $type;
return $this;
}
public function getContainerNumber(): ?string
{
return $this->containerNumber;
}
public function setContainerNumber(?string $containerNumber): static
{
$this->containerNumber = $containerNumber;
return $this;
}
public function getBillOfLading(): ?string
{
return $this->billOfLading;
}
public function setBillOfLading(?string $billOfLading): static
{
$this->billOfLading = $billOfLading;
return $this;
}
public function getShippingDate(): ?string
{
return $this->shippingDate;
}
public function setShippingDate(?string $shippingDate): static
{
$this->shippingDate = $shippingDate;
return $this;
}
public function getArrivalDate(): ?string
{
return $this->arrivalDate;
}
public function setArrivalDate(?string $arrivalDate): static
{
$this->arrivalDate = $arrivalDate;
return $this;
}
public function getUnloadingDate(): ?string
{
return $this->unloadingDate;
}
public function setUnloadingDate(?string $unloadingDate): static
{
$this->unloadingDate = $unloadingDate;
return $this;
}
public function getShippingCompany(): ?string
{
return $this->shippingCompany;
}
public function setShippingCompany(?string $shippingCompany): static
{
$this->shippingCompany = $shippingCompany;
return $this;
}
public function getShippingCompanyPhone(): ?string
{
return $this->shippingCompanyPhone;
}
public function setShippingCompanyPhone(?string $shippingCompanyPhone): static
{
$this->shippingCompanyPhone = $shippingCompanyPhone;
return $this;
}
public function getShippingCompanyEmail(): ?string
{
return $this->shippingCompanyEmail;
}
public function setShippingCompanyEmail(?string $shippingCompanyEmail): static
{
$this->shippingCompanyEmail = $shippingCompanyEmail;
return $this;
}
public function getOriginPort(): ?string
{
return $this->originPort;
}
public function setOriginPort(?string $originPort): static
{
$this->originPort = $originPort;
return $this;
}
public function getDestinationPort(): ?string
{
return $this->destinationPort;
}
public function setDestinationPort(?string $destinationPort): static
{
$this->destinationPort = $destinationPort;
return $this;
}
public function getVesselName(): ?string
{
return $this->vesselName;
}
public function setVesselName(?string $vesselName): static
{
$this->vesselName = $vesselName;
return $this;
}
public function getVoyageNumber(): ?string
{
return $this->voyageNumber;
}
public function setVoyageNumber(?string $voyageNumber): static
{
$this->voyageNumber = $voyageNumber;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getDateSubmit(): ?string
{
return $this->dateSubmit;
}
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
}

View file

@ -0,0 +1,157 @@
<?php
namespace App\Entity;
use App\Repository\ImportWorkflowStageRepository;
use Doctrine\DBAL\Types\Types;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\Ignore;
#[ORM\Entity(repositoryClass: ImportWorkflowStageRepository::class)]
class ImportWorkflowStage
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'stages')]
#[ORM\JoinColumn(nullable: false)]
#[Ignore]
private ?ImportWorkflow $importWorkflow = null;
#[ORM\Column(length: 255)]
private ?string $stage = null;
#[ORM\Column(length: 255)]
private ?string $status = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $startDate = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $endDate = null;
#[ORM\Column(type: Types::TEXT, nullable: true)]
private ?string $description = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $assignedTo = null;
#[ORM\Column(length: 255)]
private ?string $dateSubmit = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $notes = null;
public function __construct()
{
$this->dateSubmit = date('Y-m-d H:i:s');
$this->status = 'pending';
}
public function getId(): ?int
{
return $this->id;
}
public function getImportWorkflow(): ?ImportWorkflow
{
return $this->importWorkflow;
}
public function setImportWorkflow(?ImportWorkflow $importWorkflow): static
{
$this->importWorkflow = $importWorkflow;
return $this;
}
public function getStage(): ?string
{
return $this->stage;
}
public function setStage(string $stage): static
{
$this->stage = $stage;
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(string $status): static
{
$this->status = $status;
return $this;
}
public function getStartDate(): ?string
{
return $this->startDate;
}
public function setStartDate(?string $startDate): static
{
$this->startDate = $startDate;
return $this;
}
public function getEndDate(): ?string
{
return $this->endDate;
}
public function setEndDate(?string $endDate): static
{
$this->endDate = $endDate;
return $this;
}
public function getDescription(): ?string
{
return $this->description;
}
public function setDescription(?string $description): static
{
$this->description = $description;
return $this;
}
public function getAssignedTo(): ?string
{
return $this->assignedTo;
}
public function setAssignedTo(?string $assignedTo): static
{
$this->assignedTo = $assignedTo;
return $this;
}
public function getDateSubmit(): ?string
{
return $this->dateSubmit;
}
public function setDateSubmit(string $dateSubmit): static
{
$this->dateSubmit = $dateSubmit;
return $this;
}
public function getNotes(): ?string
{
return $this->notes;
}
public function setNotes(?string $notes): static
{
$this->notes = $notes;
return $this;
}
}

View file

@ -141,6 +141,21 @@ class Permission
#[ORM\Column(nullable: true)]
private ?bool $ai = null;
#[ORM\Column(nullable: true)]
private ?bool $warehouseManager = null;
#[ORM\Column(nullable: true)]
private ?bool $importWorkflow = null;
#[ORM\Column(nullable: true)]
private ?bool $requireTwoStepSell = null;
#[ORM\Column(nullable: true)]
private ?bool $requireTwoStepPayment = null;
#[ORM\Column(nullable: true)]
private ?bool $requireTwoStepStore = null;
public function getId(): ?int
{
return $this->id;
@ -649,4 +664,61 @@ class Permission
return $this;
}
public function isWarehouseManager(): ?bool
{
return $this->warehouseManager;
}
public function setWarehouseManager(?bool $warehouseManager): static
{
$this->warehouseManager = $warehouseManager;
return $this;
}
public function isImportWorkflow(): ?bool
{
return $this->importWorkflow;
}
public function setImportWorkflow(?bool $importWorkflow): static
{
$this->importWorkflow = $importWorkflow;
return $this;
}
public function isRequireTwoStepSell(): ?bool
{
return $this->requireTwoStepSell;
}
public function setRequireTwoStepSell(?bool $requireTwoStepSell): static
{
$this->requireTwoStepSell = $requireTwoStepSell;
return $this;
}
public function isRequireTwoStepPayment(): ?bool
{
return $this->requireTwoStepPayment;
}
public function setRequireTwoStepPayment(?bool $requireTwoStepPayment): static
{
$this->requireTwoStepPayment = $requireTwoStepPayment;
return $this;
}
public function isRequireTwoStepStore(): ?bool
{
return $this->requireTwoStepStore;
}
public function setRequireTwoStepStore(?bool $requireTwoStepStore): static
{
$this->requireTwoStepStore = $requireTwoStepStore;
return $this;
}
}

View file

@ -49,6 +49,15 @@ class PlugWarrantySerial
#[ORM\Column(length: 255, nullable: true)]
private ?string $notes = null;
#[ORM\Column(nullable: true)]
private ?bool $used = null;
#[ORM\Column(length: 50, nullable: true)]
private ?string $usedAt = null;
#[ORM\Column(length: 255, nullable: true)]
private ?string $usedTicketCode = null;
public function __construct()
{
$this->dateSubmit = date('Y-m-d H:i:s');
@ -168,4 +177,37 @@ class PlugWarrantySerial
$this->notes = $notes;
return $this;
}
public function isUsed(): ?bool
{
return $this->used;
}
public function setUsed(?bool $used): static
{
$this->used = $used;
return $this;
}
public function getUsedAt(): ?string
{
return $this->usedAt;
}
public function setUsedAt(?string $usedAt): static
{
$this->usedAt = $usedAt;
return $this;
}
public function getUsedTicketCode(): ?string
{
return $this->usedTicketCode;
}
public function setUsedTicketCode(?string $usedTicketCode): static
{
$this->usedTicketCode = $usedTicketCode;
return $this;
}
}

View file

@ -77,6 +77,12 @@ class StoreroomTicket
#[ORM\Column(nullable: true)]
private ?bool $canShare = null;
#[ORM\Column(length: 50, nullable: true)]
private ?string $status = null; // in_progress | done | rejected
#[ORM\Column(length: 255, nullable: true)]
private ?string $importWorkflowCode = null;
public function __construct()
{
$this->storeroomItems = new ArrayCollection();
@ -332,4 +338,26 @@ class StoreroomTicket
return $this;
}
public function getStatus(): ?string
{
return $this->status;
}
public function setStatus(?string $status): static
{
$this->status = $status;
return $this;
}
public function getImportWorkflowCode(): ?string
{
return $this->importWorkflowCode;
}
public function setImportWorkflowCode(?string $importWorkflowCode): static
{
$this->importWorkflowCode = $importWorkflowCode;
return $this;
}
}

View file

@ -144,6 +144,9 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\OneToMany(mappedBy: 'user', targetEntity: AIConversation::class, orphanRemoval: true)]
private Collection $aiConversations;
#[ORM\OneToMany(mappedBy: 'submitter', targetEntity: ImportWorkflow::class, orphanRemoval: true)]
private Collection $importWorkflows;
public function __construct()
{
$this->userTokens = new ArrayCollection();
@ -171,6 +174,7 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
$this->backBuiltModules = new ArrayCollection();
$this->PlugGhestaDocs = new ArrayCollection();
$this->aiConversations = new ArrayCollection();
$this->importWorkflows = new ArrayCollection();
}
public function getId(): ?int
@ -1066,4 +1070,28 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
return $this;
}
public function getImportWorkflows(): Collection
{
return $this->importWorkflows;
}
public function addImportWorkflow(ImportWorkflow $importWorkflow): static
{
if (!$this->importWorkflows->contains($importWorkflow)) {
$this->importWorkflows->add($importWorkflow);
$importWorkflow->setSubmitter($this);
}
return $this;
}
public function removeImportWorkflow(ImportWorkflow $importWorkflow): static
{
if ($this->importWorkflows->removeElement($importWorkflow)) {
if ($importWorkflow->getSubmitter() === $this) {
$importWorkflow->setSubmitter(null);
}
}
return $this;
}
}

View file

@ -142,8 +142,11 @@ class CommodityRepository extends ServiceEntityRepository
}
}
$query->setMaxResults($params['Take'])
->orderBy('p.id', 'ASC');
if (isset($params['Take']) && $params['Take'] !== -1) {
$query->setMaxResults($params['Take']);
}
$query->orderBy('p.id', 'ASC');
return $query->getQuery()->getResult();
}

View file

@ -0,0 +1,36 @@
<?php
namespace App\Repository;
use App\Entity\ImportWorkflowCustoms;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ImportWorkflowCustomsRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImportWorkflowCustoms::class);
}
public function findByImportWorkflow($importWorkflowId)
{
return $this->createQueryBuilder('iwc')
->andWhere('iwc.importWorkflow = :importWorkflowId')
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iwc.dateSubmit', 'ASC')
->getQuery()
->getResult();
}
public function findByDeclarationNumber($declarationNumber, $importWorkflowId)
{
return $this->createQueryBuilder('iwc')
->andWhere('iwc.declarationNumber = :declarationNumber')
->andWhere('iwc.importWorkflow = :importWorkflowId')
->setParameter('declarationNumber', $declarationNumber)
->setParameter('importWorkflowId', $importWorkflowId)
->getQuery()
->getOneOrNullResult();
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace App\Repository;
use App\Entity\ImportWorkflowDocument;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ImportWorkflowDocumentRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImportWorkflowDocument::class);
}
public function findByImportWorkflow($importWorkflowId)
{
return $this->createQueryBuilder('iwd')
->andWhere('iwd.importWorkflow = :importWorkflowId')
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iwd.dateSubmit', 'ASC')
->getQuery()
->getResult();
}
public function findByType($type, $importWorkflowId)
{
return $this->createQueryBuilder('iwd')
->andWhere('iwd.type = :type')
->andWhere('iwd.importWorkflow = :importWorkflowId')
->setParameter('type', $type)
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iwd.dateSubmit', 'ASC')
->getQuery()
->getResult();
}
}

View file

@ -0,0 +1,25 @@
<?php
namespace App\Repository;
use App\Entity\ImportWorkflowItem;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ImportWorkflowItemRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImportWorkflowItem::class);
}
public function findByImportWorkflow($importWorkflowId)
{
return $this->createQueryBuilder('iwi')
->andWhere('iwi.importWorkflow = :importWorkflowId')
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iwi.dateSubmit', 'ASC')
->getQuery()
->getResult();
}
}

View file

@ -0,0 +1,37 @@
<?php
namespace App\Repository;
use App\Entity\ImportWorkflowPayment;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ImportWorkflowPaymentRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImportWorkflowPayment::class);
}
public function findByImportWorkflow($importWorkflowId)
{
return $this->createQueryBuilder('iwp')
->andWhere('iwp.importWorkflow = :importWorkflowId')
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iwp.paymentDate', 'ASC')
->getQuery()
->getResult();
}
public function findByType($type, $importWorkflowId)
{
return $this->createQueryBuilder('iwp')
->andWhere('iwp.type = :type')
->andWhere('iwp.importWorkflow = :importWorkflowId')
->setParameter('type', $type)
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iwp.paymentDate', 'ASC')
->getQuery()
->getResult();
}
}

View file

@ -0,0 +1,66 @@
<?php
namespace App\Repository;
use App\Entity\ImportWorkflow;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ImportWorkflowRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImportWorkflow::class);
}
public function findByBusiness($businessId)
{
return $this->createQueryBuilder('iw')
->andWhere('iw.business = :businessId')
->setParameter('businessId', $businessId)
->orderBy('iw.dateSubmit', 'DESC')
->getQuery()
->getResult();
}
public function findByStatus($status, $businessId)
{
return $this->createQueryBuilder('iw')
->andWhere('iw.status = :status')
->andWhere('iw.business = :businessId')
->setParameter('status', $status)
->setParameter('businessId', $businessId)
->orderBy('iw.dateSubmit', 'DESC')
->getQuery()
->getResult();
}
public function findByCode($code, $businessId)
{
return $this->createQueryBuilder('iw')
->andWhere('iw.code = :code')
->andWhere('iw.business = :businessId')
->setParameter('code', $code)
->setParameter('businessId', $businessId)
->getQuery()
->getOneOrNullResult();
}
public function findWithDetails($id, $businessId)
{
return $this->createQueryBuilder('iw')
->leftJoin('iw.items', 'items')
->leftJoin('iw.payments', 'payments')
->leftJoin('iw.documents', 'documents')
->leftJoin('iw.stages', 'stages')
->leftJoin('iw.shipping', 'shipping')
->leftJoin('iw.customs', 'customs')
->addSelect('items', 'payments', 'documents', 'stages', 'shipping', 'customs')
->andWhere('iw.id = :id')
->andWhere('iw.business = :businessId')
->setParameter('id', $id)
->setParameter('businessId', $businessId)
->getQuery()
->getOneOrNullResult();
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace App\Repository;
use App\Entity\ImportWorkflowShipping;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ImportWorkflowShippingRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImportWorkflowShipping::class);
}
public function findByImportWorkflow($importWorkflowId)
{
return $this->createQueryBuilder('iws')
->andWhere('iws.importWorkflow = :importWorkflowId')
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iws.dateSubmit', 'ASC')
->getQuery()
->getResult();
}
public function findByType($type, $importWorkflowId)
{
return $this->createQueryBuilder('iws')
->andWhere('iws.type = :type')
->andWhere('iws.importWorkflow = :importWorkflowId')
->setParameter('type', $type)
->setParameter('importWorkflowId', $importWorkflowId)
->getQuery()
->getOneOrNullResult();
}
}

View file

@ -0,0 +1,36 @@
<?php
namespace App\Repository;
use App\Entity\ImportWorkflowStage;
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
use Doctrine\Persistence\ManagerRegistry;
class ImportWorkflowStageRepository extends ServiceEntityRepository
{
public function __construct(ManagerRegistry $registry)
{
parent::__construct($registry, ImportWorkflowStage::class);
}
public function findByImportWorkflow($importWorkflowId)
{
return $this->createQueryBuilder('iws')
->andWhere('iws.importWorkflow = :importWorkflowId')
->setParameter('importWorkflowId', $importWorkflowId)
->orderBy('iws.dateSubmit', 'ASC')
->getQuery()
->getResult();
}
public function findByStage($stage, $importWorkflowId)
{
return $this->createQueryBuilder('iws')
->andWhere('iws.stage = :stage')
->andWhere('iws.importWorkflow = :importWorkflowId')
->setParameter('stage', $stage)
->setParameter('importWorkflowId', $importWorkflowId)
->getQuery()
->getOneOrNullResult();
}
}

View file

@ -50,9 +50,10 @@ class Access
return false;
}
}
elseif($this->request->headers->get('api-key')){
elseif($this->request->headers->get('api-key') || $this->request->headers->get('X-AUTH-TOKEN')){
$rawToken = $this->request->headers->get('api-key') ?: $this->request->headers->get('X-AUTH-TOKEN');
$token = $this->em->getRepository(APIToken::class)->findOneBy([
'token'=>$this->request->headers->get('api-key')
'token'=> $rawToken
]);
if(!$token) { return false; }
@ -68,6 +69,10 @@ class Access
$bid = $token->getBid();
}
else {
// بدون BID فعال یا توکن معتبر
return false;
}
if ($this->request->headers->get('activeYear')) {
$year = $this->em->getRepository(Year::class)->findOneBy([
'id' => $this->request->headers->get('activeYear'),
@ -75,7 +80,7 @@ class Access
]);
if (!$year) { return false; }
}
elseif($this->request->headers->get('api-key')){
elseif($this->request->headers->get('api-key') || $this->request->headers->get('X-AUTH-TOKEN')){
$year = $this->em->getRepository(Year::class)->findOneBy([
'head' => true,
'bid'=>$bid
@ -126,6 +131,19 @@ class Access
elseif ($this->user && $roll == 'join' && count($this->em->getRepository(Permission::class)->findBy(['user'=>$this->user,'bid'=>$bid]))){
return $accessArray;
}
$warehousePermission = $this->em->getRepository(Permission::class)->findOneBy([
'bid'=>$bid,
'user'=>$this->user
]);
if($warehousePermission && $warehousePermission->isWarehouseManager()){
$warehouseRoles = ['commodity', 'store', 'plugWarrantyManager'];
if(in_array($roll, $warehouseRoles)){
return $accessArray;
}
}
$methodName = 'is' . ucfirst($roll);
$permission = $this->em->getRepository(Permission::class)->findOneBy([
'bid'=>$bid,

View file

@ -1060,6 +1060,26 @@ const router = createRouter({
component: () =>
import('../views/acc/inquiry/panel.vue'),
},
{
path: 'import-workflow/list',
name: 'import_workflow_list',
component: () =>
import('../views/ImportWorkflow/ImportWorkflowList.vue'),
meta: {
'title': 'مدیریت واردات کالا',
'login': true,
}
},
{
path: 'import-workflow/:id',
name: 'import_workflow_detail',
component: () =>
import('../views/ImportWorkflow/ImportWorkflowDetail.vue'),
meta: {
'title': 'جزئیات پرونده واردات',
'login': true,
}
},
],
},
{

View file

@ -198,6 +198,7 @@ export default {
{ path: '/acc/plugins/tax/invoices/list', key: 'L', label: this.$t('drawer.tax_invoices'), ctrl: true, shift: true, permission: () => this.permissions.settings && this.isPluginActive('taxsettings') },
{ path: '/acc/plugins/tax/settings', key: 'T', label: this.$t('drawer.tax_settings'), ctrl: true, shift: true, permission: () => this.permissions.settings && this.isPluginActive('taxsettings') },
{ path: '/acc/plugins/custominvoice/templates', key: 'I', label: 'قالب‌های فاکتور', ctrl: true, shift: true, permission: () => this.permissions.settings && this.isPluginActive('custominvoice') },
{ path: '/acc/import-workflow/list', key: 'I', label: 'مدیریت واردات کالا', ctrl: true, shift: true, permission: () => this.permissions.importWorkflow },
];
},
restorePermissions(shortcuts) {
@ -788,6 +789,25 @@ export default {
</v-list-item>
</v-list-group>
<v-list-subheader color="primary">{{ $t('drawer.services') }}</v-list-subheader>
<v-list-group v-show="permissions.importWorkflow">
<template v-slot:activator="{ props }">
<v-list-item class="text-dark" v-bind="props" title="مدیریت واردات کالا">
<template v-slot:prepend><v-icon icon="mdi-import" color="primary"></v-icon></template>
</v-list-item>
</template>
<v-list-item v-if="permissions.importWorkflow" to="/acc/import-workflow/list">
<v-list-item-title>
لیست پروندههای واردات
</v-list-item-title>
<template v-slot:append>
<v-tooltip text="پرونده واردات جدید" location="end">
<template v-slot:activator="{ props }">
<v-btn v-bind="props" icon="mdi-plus-box" variant="plain" @click="$router.push('/acc/import-workflow/list')" />
</template>
</v-tooltip>
</template>
</v-list-item>
</v-list-group>
<v-list-group v-show="permissions.plugRepservice && isPluginActive('repservice')">
<template v-slot:activator="{ props }">
<v-list-item class="text-dark" v-bind="props" :title="$t('drawer.repservice')">

View file

@ -402,6 +402,52 @@
</v-col>
</v-row>
<!-- بخش دسترسی انباردار -->
<v-row class="mt-4">
<v-col cols="12">
<v-card-title class="text-h6 font-weight-bold mb-4 text-primary">
<v-icon color="primary" class="me-2">mdi-warehouse</v-icon>
دسترسی انباردار
</v-card-title>
<v-alert
type="info"
variant="tonal"
class="warehouse-alert mr-4"
density="compact"
border="start"
border-color="primary"
>
<template v-slot:prepend>
<v-icon color="primary">mdi-information</v-icon>
</template>
<div class="text-body-2">
دسترسی انباردار شامل تمام بخشهای انبارداری مانند مدیریت انبارها، کالاها، حوالهها، موجودی و گارانتی میباشد.
</div>
</v-alert>
</v-col>
<v-col cols="12" md="6">
<v-card variant="outlined" class="h-100">
<v-card-text>
<v-list>
<v-list-item>
<v-switch
v-model="info.warehouseManager"
label="دسترسی کامل انباردار"
@change="savePerms('warehouseManager')"
hide-details
color="primary"
density="comfortable"
:loading="loadingSwitches.warehouseManager"
:disabled="loadingSwitches.warehouseManager"
></v-switch>
</v-list-item>
</v-list>
</v-card-text>
</v-card>
</v-col>
</v-row>
<v-row v-if="isPluginActive('accpro')" class="mt-4">
<v-col cols="12">
<v-card-title class="text-h6 font-weight-bold mb-4">بسته حسابداری پیشرفته</v-card-title>
@ -732,7 +778,8 @@ export default {
plugGhestaManager: false,
plugTaxSettings: false,
inquiry: false,
ai: false
ai: false,
warehouseManager: false
};
axios.post('/api/business/get/user/permissions',
@ -809,4 +856,16 @@ export default {
.v-switch.v-input--disabled {
opacity: 0.7;
}
.warehouse-alert {
width: 45%;
}
@media (max-width: 600px) {
.warehouse-alert {
width: 100%;
margin-right: 0px !important;
}
}
</style>