update two-step system
This commit is contained in:
parent
f137fcb0dc
commit
68bd621a58
|
@ -29,7 +29,7 @@ class ApprovalController extends AbstractController
|
||||||
EntityManagerInterface $entityManager
|
EntityManagerInterface $entityManager
|
||||||
): Response {
|
): Response {
|
||||||
try {
|
try {
|
||||||
$acc = $access->hasRole('settings');
|
$acc = $access->hasRole('store');
|
||||||
if (!$acc) {
|
if (!$acc) {
|
||||||
throw $this->createAccessDeniedException();
|
throw $this->createAccessDeniedException();
|
||||||
}
|
}
|
||||||
|
@ -82,6 +82,68 @@ class ApprovalController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/api/approval/unapprove/storeroom/{ticketCode}', name: 'api_approval_unapprove_storeroom', methods: ['POST'])]
|
||||||
|
public function unapproveStoreroomTicket(
|
||||||
|
$ticketCode,
|
||||||
|
#[CurrentUser] ?User $user,
|
||||||
|
Access $access,
|
||||||
|
LogService $logService,
|
||||||
|
EntityManagerInterface $entityManager
|
||||||
|
): Response {
|
||||||
|
try {
|
||||||
|
$acc = $access->hasRole('store');
|
||||||
|
if (!$acc) {
|
||||||
|
throw $this->createAccessDeniedException();
|
||||||
|
}
|
||||||
|
|
||||||
|
$business = $acc['bid'];
|
||||||
|
$businessSettings = $entityManager->getRepository(Business::class)->find($business->getId());
|
||||||
|
|
||||||
|
if (!$businessSettings->isRequireTwoStepApproval()) {
|
||||||
|
return $this->json(['success' => false, 'message' => 'تأیید دو مرحلهای فعال نیست']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ticket = $entityManager->getRepository(\App\Entity\StoreroomTicket::class)->findOneBy([
|
||||||
|
'code' => $ticketCode,
|
||||||
|
'bid' => $business
|
||||||
|
]);
|
||||||
|
|
||||||
|
if (!$ticket) {
|
||||||
|
return $this->json(['success' => false, 'message' => 'حواله انبار یافت نشد']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$canApprove = $this->canUserApproveStoreroomTicket($user, $businessSettings);
|
||||||
|
if (!$canApprove) {
|
||||||
|
return $this->json(['success' => false, 'message' => 'شما مجوز تأیید این حواله را ندارید']);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ticket->setIsPreview(true);
|
||||||
|
$ticket->setIsApproved(false);
|
||||||
|
$ticket->setApprovedBy(null);
|
||||||
|
|
||||||
|
$entityManager->persist($ticket);
|
||||||
|
$entityManager->flush();
|
||||||
|
|
||||||
|
$logService->insert(
|
||||||
|
'لغو تأیید حواله انبار',
|
||||||
|
"حواله انبار {$ticket->getCode()} توسط {$user->getFullName()} لغو تأیید شد",
|
||||||
|
$user,
|
||||||
|
$business
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'حواله انبار با موفقیت لغو تأیید شد'
|
||||||
|
]);
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return $this->json([
|
||||||
|
'success' => false,
|
||||||
|
'message' => 'خطا در لغو تأیید حواله انبار: ' . $e->getMessage()
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[Route('/api/approval/approve/sales/{docId}', name: 'api_approval_approve_sales', methods: ['POST'])]
|
#[Route('/api/approval/approve/sales/{docId}', name: 'api_approval_approve_sales', methods: ['POST'])]
|
||||||
public function approveSalesInvoice(
|
public function approveSalesInvoice(
|
||||||
$docId,
|
$docId,
|
||||||
|
@ -91,7 +153,7 @@ class ApprovalController extends AbstractController
|
||||||
EntityManagerInterface $entityManager
|
EntityManagerInterface $entityManager
|
||||||
): Response {
|
): Response {
|
||||||
try {
|
try {
|
||||||
$acc = $access->hasRole('settings');
|
$acc = $access->hasRole('sell');
|
||||||
if (!$acc) {
|
if (!$acc) {
|
||||||
throw $this->createAccessDeniedException();
|
throw $this->createAccessDeniedException();
|
||||||
}
|
}
|
||||||
|
@ -166,7 +228,7 @@ class ApprovalController extends AbstractController
|
||||||
EntityManagerInterface $entityManager
|
EntityManagerInterface $entityManager
|
||||||
): Response {
|
): Response {
|
||||||
try {
|
try {
|
||||||
$acc = $access->hasRole('settings');
|
$acc = $access->hasRole('sell');
|
||||||
if (!$acc) {
|
if (!$acc) {
|
||||||
throw $this->createAccessDeniedException();
|
throw $this->createAccessDeniedException();
|
||||||
}
|
}
|
||||||
|
@ -250,7 +312,7 @@ class ApprovalController extends AbstractController
|
||||||
EntityManagerInterface $entityManager
|
EntityManagerInterface $entityManager
|
||||||
): Response {
|
): Response {
|
||||||
try {
|
try {
|
||||||
$acc = $access->hasRole('settings');
|
$acc = $access->hasRole('sell');
|
||||||
if (!$acc) {
|
if (!$acc) {
|
||||||
throw $this->createAccessDeniedException();
|
throw $this->createAccessDeniedException();
|
||||||
}
|
}
|
||||||
|
@ -316,50 +378,6 @@ class ApprovalController extends AbstractController
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/approval/check-permission/{docId}', name: 'api_approval_check_permission', methods: ['GET'])]
|
|
||||||
public function checkApprovalPermission(
|
|
||||||
$docId,
|
|
||||||
#[CurrentUser] ?User $user,
|
|
||||||
Access $access,
|
|
||||||
EntityManagerInterface $entityManager
|
|
||||||
): Response {
|
|
||||||
try {
|
|
||||||
$acc = $access->hasRole('settings');
|
|
||||||
if (!$acc) {
|
|
||||||
return $this->json(['canApprove' => false, 'message' => 'دسترسی محدود']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$business = $acc['bid'];
|
|
||||||
$businessSettings = $entityManager->getRepository(Business::class)->find($business->getId());
|
|
||||||
|
|
||||||
$document = $entityManager->getRepository(HesabdariDoc::class)->findOneByIncludePreview([
|
|
||||||
'id' => $docId,
|
|
||||||
'bid' => $business
|
|
||||||
]);
|
|
||||||
|
|
||||||
if (!$document) {
|
|
||||||
return $this->json(['canApprove' => false, 'message' => 'سند یافت نشد']);
|
|
||||||
}
|
|
||||||
|
|
||||||
$canApprove = $this->canUserApproveDocument($user, $businessSettings, $document);
|
|
||||||
|
|
||||||
return $this->json([
|
|
||||||
'canApprove' => $canApprove,
|
|
||||||
'documentStatus' => [
|
|
||||||
'isPreview' => $document->isPreview(),
|
|
||||||
'isApproved' => $document->isApproved(),
|
|
||||||
'approvedBy' => $document->getApprovedBy() ? $document->getApprovedBy()->getFullName() : null
|
|
||||||
]
|
|
||||||
]);
|
|
||||||
|
|
||||||
} catch (\Exception $e) {
|
|
||||||
return $this->json([
|
|
||||||
'canApprove' => false,
|
|
||||||
'message' => 'خطا در بررسی مجوز: ' . $e->getMessage()
|
|
||||||
], 500);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private function canUserApproveDocument(User $user, Business $business, HesabdariDoc $document): bool
|
private function canUserApproveDocument(User $user, Business $business, HesabdariDoc $document): bool
|
||||||
{
|
{
|
||||||
if ($user->getEmail() === $business->getOwner()->getEmail()) {
|
if ($user->getEmail() === $business->getOwner()->getEmail()) {
|
||||||
|
@ -370,11 +388,9 @@ class ApprovalController extends AbstractController
|
||||||
|
|
||||||
switch ($documentType) {
|
switch ($documentType) {
|
||||||
case 'invoice':
|
case 'invoice':
|
||||||
return $business->getInvoiceApprover() === $user->getEmail();
|
return $business->getApproverSellInvoice() === $user->getEmail();
|
||||||
case 'warehouse':
|
case 'warehouse':
|
||||||
return $business->getWarehouseApprover() === $user->getEmail();
|
return $business->getApproverWarehouseTransfer() === $user->getEmail();
|
||||||
case 'financial':
|
|
||||||
return $business->getFinancialApprover() === $user->getEmail();
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -405,7 +421,7 @@ class ApprovalController extends AbstractController
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $business->getWarehouseApprover() === $user->getEmail();
|
return $business->getApproverWarehouseTransfer() === $user->getEmail();
|
||||||
}
|
}
|
||||||
|
|
||||||
private function canUserApproveSalesInvoice(User $user, Business $business): bool
|
private function canUserApproveSalesInvoice(User $user, Business $business): bool
|
||||||
|
@ -414,15 +430,6 @@ class ApprovalController extends AbstractController
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $business->getInvoiceApprover() === $user->getEmail();
|
return $business->getApproverSellInvoice() === $user->getEmail();
|
||||||
}
|
|
||||||
|
|
||||||
private function canUserApproveFinancialDocument(User $user, Business $business): bool
|
|
||||||
{
|
|
||||||
if ($user->getEmail() === $business->getOwner()->getEmail()) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return $business->getFinancialApprover() === $user->getEmail();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,7 +103,21 @@ class BusinessController extends AbstractController
|
||||||
]);
|
]);
|
||||||
if (!$perms)
|
if (!$perms)
|
||||||
throw $this->createAccessDeniedException();
|
throw $this->createAccessDeniedException();
|
||||||
return $this->json(Explore::ExploreBusiness($bus));
|
$result = Explore::ExploreBusiness($bus);
|
||||||
|
// Read approval settings from Business entity (only new fields)
|
||||||
|
$result['approvers'] = [
|
||||||
|
'sellInvoice' => $bus->getApproverSellInvoice(),
|
||||||
|
'buyInvoice' => $bus->getApproverBuyInvoice(),
|
||||||
|
'returnBuy' => $bus->getApproverReturnBuy(),
|
||||||
|
'returnSell' => $bus->getApproverReturnSell(),
|
||||||
|
'warehouseTransfer' => $bus->getApproverWarehouseTransfer(),
|
||||||
|
'receiveFromPersons' => $bus->getApproverReceiveFromPersons(),
|
||||||
|
'payToPersons' => $bus->getApproverPayToPersons(),
|
||||||
|
'accountingDocs' => $bus->getApproverAccountingDocs(),
|
||||||
|
'bankTransfers' => $bus->getApproverBankTransfers(),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $this->json($result);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[Route('/api/business/list/count', name: 'api_bussiness_list_count')]
|
#[Route('/api/business/list/count', name: 'api_bussiness_list_count')]
|
||||||
|
@ -246,32 +260,26 @@ class BusinessController extends AbstractController
|
||||||
$business->setWalletEnable(false);
|
$business->setWalletEnable(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (array_key_exists('requireTwoStepApproval', $params)) {
|
|
||||||
$business->setRequireTwoStepApproval((bool)$params['requireTwoStepApproval']);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set approvers
|
// Approval settings
|
||||||
if (array_key_exists('invoiceApprover', $params)) {
|
$business->setRequireTwoStepApproval((bool)$params['requireTwoStepApproval'] ?? false);
|
||||||
$business->setInvoiceApprover($params['invoiceApprover']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists('warehouseApprover', $params)) {
|
$approvers = $params['approvers'] ?? [];
|
||||||
$business->setWarehouseApprover($params['warehouseApprover']);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (array_key_exists('financialApprover', $params)) {
|
$business->setApproverSellInvoice($approvers['sellInvoice'] ?? null);
|
||||||
$business->setFinancialApprover($params['financialApprover']);
|
$business->setApproverBuyInvoice($approvers['buyInvoice'] ?? null);
|
||||||
}
|
$business->setApproverReturnBuy($approvers['returnBuy'] ?? null);
|
||||||
|
$business->setApproverReturnSell($approvers['returnSell'] ?? null);
|
||||||
|
$business->setApproverWarehouseTransfer($approvers['warehouseTransfer'] ?? null);
|
||||||
|
$business->setApproverReceiveFromPersons($approvers['receiveFromPersons'] ?? null);
|
||||||
|
$business->setApproverPayToPersons($approvers['payToPersons'] ?? null);
|
||||||
|
$business->setApproverAccountingDocs($approvers['accountingDocs'] ?? null);
|
||||||
|
$business->setApproverBankTransfers($approvers['bankTransfers'] ?? null);
|
||||||
|
|
||||||
if (array_key_exists('requireWarrantyOnDelivery', $params)) {
|
// Warranty settings
|
||||||
$business->setRequireWarrantyOnDelivery($params['requireWarrantyOnDelivery']);
|
$business->setRequireWarrantyOnDelivery($params['requireWarrantyOnDelivery'] ?? false);
|
||||||
}
|
$business->setActivationGraceDays($params['activationGraceDays'] ?? 7);
|
||||||
if (array_key_exists('activationGraceDays', $params)) {
|
$business->setMatchWarrantyToSerial($params['matchWarrantyToSerial'] ?? false);
|
||||||
$business->setActivationGraceDays($params['activationGraceDays']);
|
|
||||||
}
|
|
||||||
if (array_key_exists('matchWarrantyToSerial', $params)) {
|
|
||||||
$business->setMatchWarrantyToSerial($params['matchWarrantyToSerial']);
|
|
||||||
}
|
|
||||||
|
|
||||||
//get Money type
|
//get Money type
|
||||||
if (!array_key_exists('arzmain', $params) && $isNew) {
|
if (!array_key_exists('arzmain', $params) && $isNew) {
|
||||||
|
@ -287,9 +295,12 @@ class BusinessController extends AbstractController
|
||||||
$business->setDateSubmit(time());
|
$business->setDateSubmit(time());
|
||||||
$entityManager->persist($business);
|
$entityManager->persist($business);
|
||||||
$entityManager->flush();
|
$entityManager->flush();
|
||||||
|
|
||||||
|
// No registry usage; settings persisted on Business entity
|
||||||
if ($isNew) {
|
if ($isNew) {
|
||||||
$perms = new Permission();
|
$perms = new Permission();
|
||||||
$giftCredit = (int) $registryMGR->get('system_settings', 'gift_credit', 0);
|
$giftCreditRaw = $registryMGR->get('system_settings', 'gift_credit');
|
||||||
|
$giftCredit = (int) ($giftCreditRaw ?? 0);
|
||||||
$business->setSmsCharge($giftCredit);
|
$business->setSmsCharge($giftCredit);
|
||||||
$perms->setBid($business);
|
$perms->setBid($business);
|
||||||
$perms->setUser($this->getUser());
|
$perms->setUser($this->getUser());
|
||||||
|
|
|
@ -316,14 +316,39 @@ class Business
|
||||||
#[ORM\Column(nullable: true)]
|
#[ORM\Column(nullable: true)]
|
||||||
private ?bool $requireTwoStepApproval = null;
|
private ?bool $requireTwoStepApproval = null;
|
||||||
|
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
// Two-step approval extended configuration
|
||||||
private ?string $invoiceApprover = null;
|
#[ORM\Column(nullable: true)]
|
||||||
|
private ?bool $approvalUseSameApprover = null;
|
||||||
|
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
private ?string $warehouseApprover = null;
|
private ?string $approverAll = null;
|
||||||
|
|
||||||
#[ORM\Column(length: 255, nullable: true)]
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
private ?string $financialApprover = null;
|
private ?string $approverSellInvoice = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverBuyInvoice = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverReturnBuy = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverReturnSell = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverWarehouseTransfer = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverReceiveFromPersons = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverPayToPersons = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverAccountingDocs = null;
|
||||||
|
|
||||||
|
#[ORM\Column(length: 255, nullable: true)]
|
||||||
|
private ?string $approverBankTransfers = null;
|
||||||
|
|
||||||
#[ORM\Column(nullable: true)]
|
#[ORM\Column(nullable: true)]
|
||||||
private ?bool $requireWarrantyOnDelivery = null;
|
private ?bool $requireWarrantyOnDelivery = null;
|
||||||
|
@ -2231,36 +2256,102 @@ class Business
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getInvoiceApprover(): ?string
|
public function getApproverSellInvoice(): ?string
|
||||||
{
|
{
|
||||||
return $this->invoiceApprover;
|
return $this->approverSellInvoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setInvoiceApprover(?string $invoiceApprover): static
|
public function setApproverSellInvoice(?string $approverSellInvoice): static
|
||||||
{
|
{
|
||||||
$this->invoiceApprover = $invoiceApprover;
|
$this->approverSellInvoice = $approverSellInvoice;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getWarehouseApprover(): ?string
|
public function getApproverBuyInvoice(): ?string
|
||||||
{
|
{
|
||||||
return $this->warehouseApprover;
|
return $this->approverBuyInvoice;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setWarehouseApprover(?string $warehouseApprover): static
|
public function setApproverBuyInvoice(?string $approverBuyInvoice): static
|
||||||
{
|
{
|
||||||
$this->warehouseApprover = $warehouseApprover;
|
$this->approverBuyInvoice = $approverBuyInvoice;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getFinancialApprover(): ?string
|
public function getApproverReturnBuy(): ?string
|
||||||
{
|
{
|
||||||
return $this->financialApprover;
|
return $this->approverReturnBuy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function setFinancialApprover(?string $financialApprover): static
|
public function setApproverReturnBuy(?string $approverReturnBuy): static
|
||||||
{
|
{
|
||||||
$this->financialApprover = $financialApprover;
|
$this->approverReturnBuy = $approverReturnBuy;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApproverReturnSell(): ?string
|
||||||
|
{
|
||||||
|
return $this->approverReturnSell;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setApproverReturnSell(?string $approverReturnSell): static
|
||||||
|
{
|
||||||
|
$this->approverReturnSell = $approverReturnSell;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApproverWarehouseTransfer(): ?string
|
||||||
|
{
|
||||||
|
return $this->approverWarehouseTransfer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setApproverWarehouseTransfer(?string $approverWarehouseTransfer): static
|
||||||
|
{
|
||||||
|
$this->approverWarehouseTransfer = $approverWarehouseTransfer;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApproverReceiveFromPersons(): ?string
|
||||||
|
{
|
||||||
|
return $this->approverReceiveFromPersons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setApproverReceiveFromPersons(?string $approverReceiveFromPersons): static
|
||||||
|
{
|
||||||
|
$this->approverReceiveFromPersons = $approverReceiveFromPersons;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApproverPayToPersons(): ?string
|
||||||
|
{
|
||||||
|
return $this->approverPayToPersons;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setApproverPayToPersons(?string $approverPayToPersons): static
|
||||||
|
{
|
||||||
|
$this->approverPayToPersons = $approverPayToPersons;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApproverAccountingDocs(): ?string
|
||||||
|
{
|
||||||
|
return $this->approverAccountingDocs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setApproverAccountingDocs(?string $approverAccountingDocs): static
|
||||||
|
{
|
||||||
|
$this->approverAccountingDocs = $approverAccountingDocs;
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApproverBankTransfers(): ?string
|
||||||
|
{
|
||||||
|
return $this->approverBankTransfers;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setApproverBankTransfers(?string $approverBankTransfers): static
|
||||||
|
{
|
||||||
|
$this->approverBankTransfers = $approverBankTransfers;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -579,9 +579,17 @@ class Explore
|
||||||
'walletEnabled' => $item->isWalletEnable(),
|
'walletEnabled' => $item->isWalletEnable(),
|
||||||
'walletMatchBank' => $item->getWalletMatchBank() ? $item->getWalletMatchBank()->getId() : null,
|
'walletMatchBank' => $item->getWalletMatchBank() ? $item->getWalletMatchBank()->getId() : null,
|
||||||
'requireTwoStepApproval' => $item->isRequireTwoStepApproval(),
|
'requireTwoStepApproval' => $item->isRequireTwoStepApproval(),
|
||||||
'invoiceApprover' => $item->getInvoiceApprover(),
|
'approvers' => [
|
||||||
'warehouseApprover' => $item->getWarehouseApprover(),
|
'sellInvoice' => $item->getApproverSellInvoice(),
|
||||||
'financialApprover' => $item->getFinancialApprover(),
|
'buyInvoice' => $item->getApproverBuyInvoice(),
|
||||||
|
'returnBuy' => $item->getApproverReturnBuy(),
|
||||||
|
'returnSell' => $item->getApproverReturnSell(),
|
||||||
|
'warehouseTransfer' => $item->getApproverWarehouseTransfer(),
|
||||||
|
'receiveFromPersons' => $item->getApproverReceiveFromPersons(),
|
||||||
|
'payToPersons' => $item->getApproverPayToPersons(),
|
||||||
|
'accountingDocs' => $item->getApproverAccountingDocs(),
|
||||||
|
'bankTransfers' => $item->getApproverBankTransfers(),
|
||||||
|
],
|
||||||
'updateSellPrice' => $item->isCommodityUpdateSellPriceAuto(),
|
'updateSellPrice' => $item->isCommodityUpdateSellPriceAuto(),
|
||||||
'updateBuyPrice' => $item->isCommodityUpdateBuyPriceAuto(),
|
'updateBuyPrice' => $item->isCommodityUpdateBuyPriceAuto(),
|
||||||
'requireWarrantyOnDelivery' => $item->getRequireWarrantyOnDelivery(),
|
'requireWarrantyOnDelivery' => $item->getRequireWarrantyOnDelivery(),
|
||||||
|
|
|
@ -24,11 +24,9 @@ export function canApproveDocument(businessSettings, currentUserEmail, isBusines
|
||||||
// Check specific approver based on document type
|
// Check specific approver based on document type
|
||||||
switch (documentType) {
|
switch (documentType) {
|
||||||
case 'invoice':
|
case 'invoice':
|
||||||
return businessSettings.invoiceApprover === currentUserEmail;
|
return businessSettings.approvers.sellInvoice === currentUserEmail;
|
||||||
case 'warehouse':
|
case 'warehouse':
|
||||||
return businessSettings.warehouseApprover === currentUserEmail;
|
return businessSettings.approvers.warehouseTransfer === currentUserEmail;
|
||||||
case 'financial':
|
|
||||||
return businessSettings.financialApprover === currentUserEmail;
|
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@
|
||||||
</v-btn>
|
</v-btn>
|
||||||
</template>
|
</template>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-subheader color="primary" v-if="business.requireTwoStepApproval">وضعیت تایید</v-list-subheader>
|
<v-list-subheader color="primary" v-if="checkApprover()">وضعیت تایید</v-list-subheader>
|
||||||
<v-list-item class="text-dark" title="تایید فاکتورهای انتخابی" @click="approveSelectedInvoices"
|
<v-list-item class="text-dark" title="تایید فاکتورهای انتخابی" @click="approveSelectedInvoices"
|
||||||
v-if="business.requireTwoStepApproval">
|
v-if="checkApprover()">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-icon color="green" icon="mdi-check-decagram"></v-icon>
|
<v-icon color="green" icon="mdi-check-decagram"></v-icon>
|
||||||
</template>
|
</template>
|
||||||
|
@ -404,7 +404,7 @@ export default defineComponent({
|
||||||
invoiceIndex: true
|
invoiceIndex: true
|
||||||
},
|
},
|
||||||
plugins: {},
|
plugins: {},
|
||||||
business: { requireTwoStepApproval: false, invoiceApprover: null },
|
business: { requireTwoStepApproval: false, approvers: { sellInvoice: null } },
|
||||||
currentUser: { email: '', owner: false },
|
currentUser: { email: '', owner: false },
|
||||||
sumSelected: 0,
|
sumSelected: 0,
|
||||||
sumSelectedProfit: 0,
|
sumSelectedProfit: 0,
|
||||||
|
@ -507,6 +507,9 @@ export default defineComponent({
|
||||||
isPluginActive(pluginCode) {
|
isPluginActive(pluginCode) {
|
||||||
return this.plugins && this.plugins[pluginCode] !== undefined;
|
return this.plugins && this.plugins[pluginCode] !== undefined;
|
||||||
},
|
},
|
||||||
|
checkApprover() {
|
||||||
|
return this.business.requireTwoStepApproval && (this.business.approvers.sellInvoice == this.currentUser.email || this.currentUser.owner === true);
|
||||||
|
},
|
||||||
async loadPlugins() {
|
async loadPlugins() {
|
||||||
try {
|
try {
|
||||||
const response = await axios.post('/api/plugin/get/actives');
|
const response = await axios.post('/api/plugin/get/actives');
|
||||||
|
@ -519,10 +522,10 @@ export default defineComponent({
|
||||||
async loadBusinessInfo() {
|
async loadBusinessInfo() {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/business/get/info/' + localStorage.getItem('activeBid'));
|
const response = await axios.get('/api/business/get/info/' + localStorage.getItem('activeBid'));
|
||||||
this.business = response.data || { requireTwoStepApproval: false, invoiceApprover: null };
|
this.business = response.data || { requireTwoStepApproval: false, approvers: { sellInvoice: null } };
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error loading business info:', error);
|
console.error('Error loading business info:', error);
|
||||||
this.business = { requireTwoStepApproval: false, invoiceApprover: null };
|
this.business = { requireTwoStepApproval: false, approvers: { sellInvoice: null } };
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
async loadCurrentUser() {
|
async loadCurrentUser() {
|
||||||
|
@ -639,11 +642,11 @@ export default defineComponent({
|
||||||
return 'success';
|
return 'success';
|
||||||
},
|
},
|
||||||
canShowApprovalButton(item) {
|
canShowApprovalButton(item) {
|
||||||
if (!this.business?.requireTwoStepApproval) return false;
|
if (!this.checkApprover()) return false;
|
||||||
|
|
||||||
if (item?.isApproved || (!item?.isPreview && !item?.isApproved)) return false;
|
if (item?.isApproved) return false;
|
||||||
|
|
||||||
return this.business?.invoiceApprover === this.currentUser?.email || this.currentUser?.owner === true;
|
return true;
|
||||||
},
|
},
|
||||||
async approveInvoice(code) {
|
async approveInvoice(code) {
|
||||||
try {
|
try {
|
||||||
|
@ -660,7 +663,7 @@ export default defineComponent({
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
canShowUnapproveButton(item) {
|
canShowUnapproveButton(item) {
|
||||||
return !this.canShowApprovalButton(item);
|
return !this.canShowApprovalButton(item) && this.checkApprover();
|
||||||
},
|
},
|
||||||
async unapproveInvoice(code) {
|
async unapproveInvoice(code) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -24,10 +24,13 @@
|
||||||
<v-tab value="2">
|
<v-tab value="2">
|
||||||
{{ $t('dialog.global_settings') }}
|
{{ $t('dialog.global_settings') }}
|
||||||
</v-tab>
|
</v-tab>
|
||||||
<v-tab value="3" v-if="isPluginActive('warranty')">
|
<v-tab value="3" v-if="isPluginActive('accpro')">
|
||||||
|
تایید اسناد
|
||||||
|
</v-tab>
|
||||||
|
<v-tab value="4" v-if="isPluginActive('warranty')">
|
||||||
{{ $t('dialog.warranty_settings') }}
|
{{ $t('dialog.warranty_settings') }}
|
||||||
</v-tab>
|
</v-tab>
|
||||||
<v-tab value="4" v-if="showBackupTab">
|
<v-tab value="5" v-if="showBackupTab">
|
||||||
نسخه پشتیبان
|
نسخه پشتیبان
|
||||||
</v-tab>
|
</v-tab>
|
||||||
</v-tabs>
|
</v-tabs>
|
||||||
|
@ -198,7 +201,170 @@
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
<v-tabs-window-item value="3" v-if="isPluginActive('warranty')">
|
|
||||||
|
<v-tabs-window-item value="3" v-if="isPluginActive('accpro')">
|
||||||
|
<v-card>
|
||||||
|
<v-card-text>
|
||||||
|
<h3 class="text-primary mb-6">تایید اسناد</h3>
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12" md="8">
|
||||||
|
<v-card variant="outlined" class="mb-6">
|
||||||
|
<v-card-text>
|
||||||
|
<v-switch
|
||||||
|
v-model="content.requireTwoStepApproval"
|
||||||
|
label="فعالسازی تایید دومرحلهای برای اسناد"
|
||||||
|
color="primary"
|
||||||
|
hide-details
|
||||||
|
class="mb-2"
|
||||||
|
></v-switch>
|
||||||
|
<div class="text-body-2 text-medium-emphasis mb-2">
|
||||||
|
با فعالسازی این گزینه، تمام اسناد انتخابی نیاز به تایید خواهند داشت.
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<v-expand-transition>
|
||||||
|
<div v-if="content.requireTwoStepApproval">
|
||||||
|
<v-divider class="my-4"></v-divider>
|
||||||
|
<h4 class="text-subtitle-1 mb-3">تعیین تاییدکنندگان</h4>
|
||||||
|
|
||||||
|
<v-row>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.sellInvoice"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده فاکتور فروش"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.buyInvoice"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده فاکتور خرید"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.returnBuy"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده برگشت از خرید"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.returnSell"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده برگشت از فروش"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.warehouseTransfer"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده حواله انبار"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.receiveFromPersons"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده دریافت از اشخاص"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.payToPersons"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده پرداخت به اشخاص"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.accountingDocs"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده اسناد حسابداری"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="6">
|
||||||
|
<v-select
|
||||||
|
v-model="content.approvers.bankTransfers"
|
||||||
|
:items="users"
|
||||||
|
item-title="name"
|
||||||
|
item-value="email"
|
||||||
|
label="تاییدکننده انتقالها (بانکداری)"
|
||||||
|
variant="outlined"
|
||||||
|
density="compact"
|
||||||
|
clearable
|
||||||
|
/>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
|
||||||
|
<div class="text-caption text-medium-emphasis mt-4">
|
||||||
|
<v-icon size="small" color="info" class="me-1">mdi-information</v-icon>
|
||||||
|
در صورت عدم انتخاب تاییدکننده برای هر بخش، فقط مدیر کسب و کار مجاز به تایید است.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</v-expand-transition>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="12" md="4">
|
||||||
|
<v-card variant="outlined">
|
||||||
|
<v-card-title class="text-h6 text-primary">
|
||||||
|
<v-icon icon="mdi-information-outline" class="mr-2"></v-icon>
|
||||||
|
نکات
|
||||||
|
</v-card-title>
|
||||||
|
<v-card-text>
|
||||||
|
<v-list density="compact">
|
||||||
|
<v-list-item title="صاحب کسبوکار همیشه مجاز به تایید همه اسناد است." />
|
||||||
|
<v-list-item title="میتوانید یک تاییدکننده برای همه یا تاییدکنندههای مجزا تعیین کنید." />
|
||||||
|
</v-list>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-card-text>
|
||||||
|
</v-card>
|
||||||
|
</v-tabs-window-item>
|
||||||
|
<v-tabs-window-item value="4" v-if="isPluginActive('warranty')">
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<h3 class="text-primary mb-6">تنظیمات گارانتی</h3>
|
<h3 class="text-primary mb-6">تنظیمات گارانتی</h3>
|
||||||
|
@ -370,126 +536,7 @@
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
|
|
||||||
<!-- تایید دومرحلهای -->
|
|
||||||
<v-card v-if="isPluginActive('accpro')" variant="outlined" class="mb-6">
|
|
||||||
<v-card-title class="text-h6 text-primary">
|
|
||||||
<v-icon icon="mdi-shield-check" class="mr-2"></v-icon>
|
|
||||||
تایید دومرحلهای
|
|
||||||
</v-card-title>
|
|
||||||
<v-card-text>
|
|
||||||
<v-switch
|
|
||||||
v-model="content.requireTwoStepApproval"
|
|
||||||
label="فعالسازی تایید دومرحلهای برای اسناد"
|
|
||||||
color="primary"
|
|
||||||
hide-details
|
|
||||||
class="mb-2"
|
|
||||||
></v-switch>
|
|
||||||
<div class="text-body-2 text-medium-emphasis mb-2">
|
|
||||||
با فعالسازی این گزینه، تمام فاکتورها، حوالههای انبار، دریافتها و پرداختها نیاز به تایید مدیر خواهند داشت.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<v-expand-transition>
|
|
||||||
<div v-if="content.requireTwoStepApproval">
|
|
||||||
<v-divider class="my-4"></v-divider>
|
|
||||||
<h4 class="text-subtitle-1 mb-3">تعیین تاییدکنندگان</h4>
|
|
||||||
<v-row>
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-select
|
|
||||||
v-model="content.invoiceApprover"
|
|
||||||
:items="users"
|
|
||||||
item-title="name"
|
|
||||||
item-value="email"
|
|
||||||
label="تاییدکننده فاکتور فروش"
|
|
||||||
variant="outlined"
|
|
||||||
density="compact"
|
|
||||||
clearable
|
|
||||||
hint="کاربری که میتواند فاکتورهای فروش را تایید کند"
|
|
||||||
persistent-hint
|
|
||||||
>
|
|
||||||
<template v-slot:item="{ item, props }">
|
|
||||||
<v-list-item v-bind="props">
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<v-icon
|
|
||||||
:color="item.owner ? 'success' : 'primary'"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
{{ item.owner ? 'mdi-crown' : 'mdi-account' }}
|
|
||||||
</v-icon>
|
|
||||||
</template>
|
|
||||||
<v-list-item-title>{{ item.name }}</v-list-item-title>
|
|
||||||
<v-list-item-subtitle>{{ item.email }}</v-list-item-subtitle>
|
|
||||||
</v-list-item>
|
|
||||||
</template>
|
|
||||||
</v-select>
|
|
||||||
<div class="text-caption text-medium-emphasis mt-1">
|
|
||||||
این کاربر افزون بر مدیر کسب و کار میتواند فاکتورهای فروش را تایید کند
|
|
||||||
</div>
|
|
||||||
</v-col>
|
|
||||||
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-select
|
|
||||||
v-model="content.warehouseApprover"
|
|
||||||
:items="users"
|
|
||||||
item-title="name"
|
|
||||||
item-value="email"
|
|
||||||
label="تاییدکننده حواله انبار"
|
|
||||||
variant="outlined"
|
|
||||||
density="compact"
|
|
||||||
clearable
|
|
||||||
hint="کاربری که میتواند حوالههای انبار را تایید کند"
|
|
||||||
persistent-hint
|
|
||||||
>
|
|
||||||
<template v-slot:item="{ item, props }">
|
|
||||||
<v-list-item v-bind="props">
|
|
||||||
<template v-slot:prepend>
|
|
||||||
<v-icon
|
|
||||||
:color="item.owner ? 'success' : 'primary'"
|
|
||||||
size="small"
|
|
||||||
>
|
|
||||||
{{ item.owner ? 'mdi-crown' : 'mdi-account' }}
|
|
||||||
</v-icon>
|
|
||||||
</template>
|
|
||||||
<v-list-item-title>{{ item.name }}</v-list-item-title>
|
|
||||||
<v-list-item-subtitle>{{ item.email }}</v-list-item-subtitle>
|
|
||||||
</v-list-item>
|
|
||||||
</template>
|
|
||||||
</v-select>
|
|
||||||
<div class="text-caption text-medium-emphasis mt-1">
|
|
||||||
این کاربر افزون بر مدیر کسب و کار میتواند حوالههای انبار را تایید کند
|
|
||||||
</div>
|
|
||||||
</v-col>
|
|
||||||
|
|
||||||
<!-- تاییدکننده دریافت و پرداخت مالی (غیرفعال فعلاً) -->
|
|
||||||
<!--
|
|
||||||
<v-col cols="12">
|
|
||||||
<v-select
|
|
||||||
v-model="content.financialApprover"
|
|
||||||
:items="users"
|
|
||||||
item-title="name"
|
|
||||||
item-value="email"
|
|
||||||
label="تاییدکننده دریافت و پرداخت مالی"
|
|
||||||
variant="outlined"
|
|
||||||
density="compact"
|
|
||||||
clearable
|
|
||||||
hint="کاربری که میتواند دریافتها و پرداختها را تایید کند"
|
|
||||||
persistent-hint
|
|
||||||
/>
|
|
||||||
</v-col>
|
|
||||||
-->
|
|
||||||
</v-row>
|
|
||||||
|
|
||||||
<div class="text-caption text-medium-emphasis">
|
|
||||||
<v-icon size="small" color="info" class="me-1">mdi-information</v-icon>
|
|
||||||
در صورت عدم انتخاب تاییدکننده، فقط مدیر کسب و کار میتواند اسناد را تایید کند
|
|
||||||
</div>
|
|
||||||
<div class="text-caption text-medium-emphasis mt-2">
|
|
||||||
<v-icon size="small" color="success" class="me-1">mdi-check-circle</v-icon>
|
|
||||||
<strong>نکته:</strong> صاحب کسب و کار همیشه میتواند تمام اسناد را تأیید کند و نیازی به تعیین مجدد ندارد
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</v-expand-transition>
|
|
||||||
</v-card-text>
|
|
||||||
</v-card>
|
|
||||||
|
|
||||||
<v-card variant="outlined">
|
<v-card variant="outlined">
|
||||||
<v-card-title class="text-h6 text-primary">
|
<v-card-title class="text-h6 text-primary">
|
||||||
|
@ -594,7 +641,7 @@
|
||||||
</v-card-text>
|
</v-card-text>
|
||||||
</v-card>
|
</v-card>
|
||||||
</v-tabs-window-item>
|
</v-tabs-window-item>
|
||||||
<v-tabs-window-item value="4" v-if="showBackupTab">
|
<v-tabs-window-item value="5" v-if="showBackupTab">
|
||||||
<v-card>
|
<v-card>
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<h3 class="text-primary mb-4">نسخه پشتیبان از اطلاعات کسب و کار</h3>
|
<h3 class="text-primary mb-4">نسخه پشتیبان از اطلاعات کسب و کار</h3>
|
||||||
|
@ -743,9 +790,17 @@ export default {
|
||||||
walletEnabled: false,
|
walletEnabled: false,
|
||||||
walletMatchBank: null,
|
walletMatchBank: null,
|
||||||
requireTwoStepApproval: false,
|
requireTwoStepApproval: false,
|
||||||
invoiceApprover: null,
|
approvers: {
|
||||||
warehouseApprover: null,
|
sellInvoice: null,
|
||||||
financialApprover: null,
|
buyInvoice: null,
|
||||||
|
returnBuy: null,
|
||||||
|
returnSell: null,
|
||||||
|
warehouseTransfer: null,
|
||||||
|
receiveFromPersons: null,
|
||||||
|
payToPersons: null,
|
||||||
|
accountingDocs: null,
|
||||||
|
bankTransfers: null
|
||||||
|
},
|
||||||
year: {
|
year: {
|
||||||
startShamsi: '',
|
startShamsi: '',
|
||||||
endShamsi: '',
|
endShamsi: '',
|
||||||
|
@ -871,9 +926,7 @@ export default {
|
||||||
'walletEnabled': this.content.walletEnabled,
|
'walletEnabled': this.content.walletEnabled,
|
||||||
'walletMatchBank': this.content.walletMatchBank,
|
'walletMatchBank': this.content.walletMatchBank,
|
||||||
'requireTwoStepApproval': this.content.requireTwoStepApproval,
|
'requireTwoStepApproval': this.content.requireTwoStepApproval,
|
||||||
'invoiceApprover': this.content.invoiceApprover,
|
'approvers': this.content.approvers,
|
||||||
'warehouseApprover': this.content.warehouseApprover,
|
|
||||||
'financialApprover': this.content.financialApprover,
|
|
||||||
'year': this.content.year,
|
'year': this.content.year,
|
||||||
'commodityUpdateBuyPriceAuto': this.content.updateBuyPrice,
|
'commodityUpdateBuyPriceAuto': this.content.updateBuyPrice,
|
||||||
'commodityUpdateSellPriceAuto': this.content.updateSellPrice,
|
'commodityUpdateSellPriceAuto': this.content.updateSellPrice,
|
||||||
|
@ -924,19 +977,11 @@ export default {
|
||||||
this.content.walletMatchBank = this.content.walletMatchBank.id;
|
this.content.walletMatchBank = this.content.walletMatchBank.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
// اطمینان از وجود فیلدهای تأییدکننده
|
// اطمینان از وجود فیلدهای تایید اسناد
|
||||||
if (!this.content.hasOwnProperty('invoiceApprover')) {
|
if (!this.content.hasOwnProperty('requireTwoStepApproval')) this.content.requireTwoStepApproval = false;
|
||||||
this.content.invoiceApprover = null;
|
if (!this.content.hasOwnProperty('approvers')) this.content.approvers = {};
|
||||||
}
|
const approverKeys = ['sellInvoice','buyInvoice','returnBuy','returnSell','warehouseTransfer','receiveFromPersons','payToPersons','accountingDocs','bankTransfers'];
|
||||||
if (!this.content.hasOwnProperty('warehouseApprover')) {
|
approverKeys.forEach(k => { if (!this.content.approvers.hasOwnProperty(k)) this.content.approvers[k] = null; });
|
||||||
this.content.warehouseApprover = null;
|
|
||||||
}
|
|
||||||
if (!this.content.hasOwnProperty('financialApprover')) {
|
|
||||||
this.content.financialApprover = null;
|
|
||||||
}
|
|
||||||
if (!this.content.hasOwnProperty('requireTwoStepApproval')) {
|
|
||||||
this.content.requireTwoStepApproval = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// سپس سایر دادهها را بارگذاری کن
|
// سپس سایر دادهها را بارگذاری کن
|
||||||
const [moneyResponse, banksResponse, usersResponse, pluginsResponse] = await Promise.all([
|
const [moneyResponse, banksResponse, usersResponse, pluginsResponse] = await Promise.all([
|
||||||
|
|
|
@ -81,6 +81,12 @@
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>تایید حواله</v-list-item-title>
|
<v-list-item-title>تایید حواله</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
<v-list-item v-if="canShowUnapproveButton(item)" @click="unapproveTicket(item.code)">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon color="red">mdi-cancel</v-icon>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>لغو تایید حواله</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
<v-list-item @click="deleteTicket('output', item.code)">
|
<v-list-item @click="deleteTicket('output', item.code)">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-icon color="error">mdi-delete</v-icon>
|
<v-icon color="error">mdi-delete</v-icon>
|
||||||
|
@ -140,6 +146,12 @@
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>تایید حواله</v-list-item-title>
|
<v-list-item-title>تایید حواله</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
<v-list-item v-if="canShowUnapproveButton(item)" @click="unapproveTicket(item.code)">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon color="red">mdi-cancel</v-icon>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>لغو تایید حواله</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
<v-list-item @click="deleteTicket('input', item.code)">
|
<v-list-item @click="deleteTicket('input', item.code)">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-icon color="error">mdi-delete</v-icon>
|
<v-icon color="error">mdi-delete</v-icon>
|
||||||
|
@ -199,6 +211,12 @@
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>تایید حواله</v-list-item-title>
|
<v-list-item-title>تایید حواله</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
<v-list-item v-if="canShowUnapproveButton(item)" @click="unapproveTicket(item.code)">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon color="red">mdi-cancel</v-icon>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>لغو تایید حواله</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
<v-list-item @click="deleteTicket('transfer', item.code)">
|
<v-list-item @click="deleteTicket('transfer', item.code)">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-icon color="error">mdi-delete</v-icon>
|
<v-icon color="error">mdi-delete</v-icon>
|
||||||
|
@ -258,6 +276,12 @@
|
||||||
</template>
|
</template>
|
||||||
<v-list-item-title>تایید حواله</v-list-item-title>
|
<v-list-item-title>تایید حواله</v-list-item-title>
|
||||||
</v-list-item>
|
</v-list-item>
|
||||||
|
<v-list-item v-if="canShowUnapproveButton(item)" @click="unapproveTicket(item.code)">
|
||||||
|
<template v-slot:prepend>
|
||||||
|
<v-icon color="red">mdi-cancel</v-icon>
|
||||||
|
</template>
|
||||||
|
<v-list-item-title>لغو تایید حواله</v-list-item-title>
|
||||||
|
</v-list-item>
|
||||||
<v-list-item @click="deleteTicket('waste', item.code)">
|
<v-list-item @click="deleteTicket('waste', item.code)">
|
||||||
<template v-slot:prepend>
|
<template v-slot:prepend>
|
||||||
<v-icon color="error">mdi-delete</v-icon>
|
<v-icon color="error">mdi-delete</v-icon>
|
||||||
|
@ -381,7 +405,7 @@ const wasteSubTab = ref<'approved' | 'pending'>('approved');
|
||||||
const showColumnDialog = ref(false);
|
const showColumnDialog = ref(false);
|
||||||
const business = ref({
|
const business = ref({
|
||||||
requireTwoStepApproval: false,
|
requireTwoStepApproval: false,
|
||||||
warehouseApprover: null
|
approvers: { warehouseTransfer: null }
|
||||||
});
|
});
|
||||||
const currentUser = ref({ email: '', owner: false });
|
const currentUser = ref({ email: '', owner: false });
|
||||||
|
|
||||||
|
@ -483,10 +507,10 @@ const displayWasteItems = computed(() => {
|
||||||
const loadBusinessInfo = async () => {
|
const loadBusinessInfo = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await axios.get('/api/business/get/info/' + localStorage.getItem('activeBid'));
|
const response = await axios.get('/api/business/get/info/' + localStorage.getItem('activeBid'));
|
||||||
business.value = response.data || { requireTwoStepApproval: false, warehouseApprover: null };
|
business.value = response.data || { requireTwoStepApproval: false, approvers: { warehouseTransfer: null } };
|
||||||
} catch (error: any) {
|
} catch (error: any) {
|
||||||
console.error('Error loading business info:', error);
|
console.error('Error loading business info:', error);
|
||||||
business.value = { requireTwoStepApproval: false, warehouseApprover: null };
|
business.value = { requireTwoStepApproval: false, approvers: { warehouseTransfer: null } };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -525,12 +549,18 @@ const loadData = async () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const checkApprover = () => {
|
||||||
|
return business.value.requireTwoStepApproval && (business.value.approvers.warehouseTransfer === currentUser.value.email || currentUser.value.owner === true);
|
||||||
|
};
|
||||||
|
|
||||||
const canShowApprovalButton = (item: Ticket) => {
|
const canShowApprovalButton = (item: Ticket) => {
|
||||||
if (!business.value.requireTwoStepApproval) return false;
|
if (!checkApprover()) return false;
|
||||||
|
|
||||||
if (item?.approved) return false;
|
if (item?.approved) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
return business.value.warehouseApprover === currentUser.value.email || currentUser.value.owner === true;
|
const canShowUnapproveButton = (item: Ticket) => {
|
||||||
|
return !canShowApprovalButton(item) && checkApprover();
|
||||||
};
|
};
|
||||||
|
|
||||||
const approveTicket = async (code: string) => {
|
const approveTicket = async (code: string) => {
|
||||||
|
@ -548,6 +578,21 @@ const approveTicket = async (code: string) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const unapproveTicket = async (code: string) => {
|
||||||
|
try {
|
||||||
|
loading.value = true;
|
||||||
|
await axios.post(`/api/approval/unapprove/storeroom/${code}`);
|
||||||
|
|
||||||
|
await loadData();
|
||||||
|
|
||||||
|
snackbar.value = { show: true, message: 'حواله لغو تایید شد', color: 'success' };
|
||||||
|
} catch (error: any) {
|
||||||
|
snackbar.value = { show: true, message: 'خطا در لغو تایید حواله: ' + (error.response?.data?.message || error.message), color: 'error' };
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const getApprovalStatusText = (item: Ticket) => {
|
const getApprovalStatusText = (item: Ticket) => {
|
||||||
if (!business.value.requireTwoStepApproval) return 'تایید دو مرحلهای غیرفعال';
|
if (!business.value.requireTwoStepApproval) return 'تایید دو مرحلهای غیرفعال';
|
||||||
|
|
||||||
|
|
|
@ -1290,31 +1290,31 @@ export default {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input-section >>> .v-field__field {
|
.input-section :deep(.v-field__field) {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-input >>> .v-input__control {
|
.custom-input :deep(.v-input__control) {
|
||||||
min-height: 60px;
|
min-height: 60px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-input >>> .v-text-field__details {
|
.custom-input :deep(.v-text-field__details) {
|
||||||
margin-top: 8px;
|
margin-top: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-input >>> .v-input__slot {
|
.custom-input :deep(.v-input__slot) {
|
||||||
border-radius: 12px !important;
|
border-radius: 12px !important;
|
||||||
background: #f8fafc;
|
background: #f8fafc;
|
||||||
border: 2px solid #e2e8f0 !important;
|
border: 2px solid #e2e8f0 !important;
|
||||||
transition: all 0.3s ease;
|
transition: all 0.3s ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-input >>> .v-input__slot:hover {
|
.custom-input :deep(.v-input__slot:hover) {
|
||||||
border-color: #3b82f6 !important;
|
border-color: #3b82f6 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-input >>> .v-text-field--focused .v-input__slot {
|
.custom-input :deep(.v-text-field--focused .v-input__slot) {
|
||||||
border-color: #3b82f6 !important;
|
border-color: #3b82f6 !important;
|
||||||
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
||||||
}
|
}
|
||||||
|
@ -1342,7 +1342,7 @@ export default {
|
||||||
transition: all 0.3s ease !important;
|
transition: all 0.3s ease !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.primary-btn >>> .v-btn__content {
|
.primary-btn :deep(.v-btn__content) {
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
|
@ -1459,7 +1459,7 @@ export default {
|
||||||
font-size: 1.5rem;
|
font-size: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom-input >>> .v-input__control {
|
.custom-input :deep(.v-input__control) {
|
||||||
min-height: 50px;
|
min-height: 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1833,7 +1833,7 @@ export default {
|
||||||
min-height: 40px !important;
|
min-height: 40px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.footer-link-btn >>> .v-btn__content {
|
.footer-link-btn :deep(.v-btn__content) {
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
|
@ -2210,7 +2210,7 @@ export default {
|
||||||
transition: all 0.3s ease !important;
|
transition: all 0.3s ease !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.back-btn >>> .v-btn__content {
|
.back-btn :deep(.v-btn__content) {
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
|
@ -2234,7 +2234,7 @@ export default {
|
||||||
transition: all 0.3s ease !important;
|
transition: all 0.3s ease !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.success-btn >>> .v-btn__content {
|
.success-btn :deep(.v-btn__content) {
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
|
@ -2256,7 +2256,7 @@ export default {
|
||||||
transition: all 0.3s ease !important;
|
transition: all 0.3s ease !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error-btn >>> .v-btn__content {
|
.error-btn :deep(.v-btn__content) {
|
||||||
gap: 8px !important;
|
gap: 8px !important;
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center !important;
|
align-items: center !important;
|
||||||
|
|
Loading…
Reference in a new issue