diff --git a/hesabixCore/migrations/Version20241220000000.php b/hesabixCore/migrations/Version20241220000000.php deleted file mode 100644 index 3d12ad1..0000000 --- a/hesabixCore/migrations/Version20241220000000.php +++ /dev/null @@ -1,40 +0,0 @@ -addSql('ALTER TABLE chat_channel ADD member_count INT NOT NULL DEFAULT 0'); - - // Update existing channels with correct member count - $this->addSql(' - UPDATE chat_channel c - SET member_count = ( - SELECT COUNT(*) - FROM chat_channel_member m - WHERE m.channel_id = c.id AND m.is_active = 1 - ) - '); - } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE chat_channel DROP member_count'); - } -} \ No newline at end of file diff --git a/hesabixCore/migrations/Version20250809100001.php b/hesabixCore/migrations/Version20250809100001.php deleted file mode 100644 index afc4739..0000000 --- a/hesabixCore/migrations/Version20250809100001.php +++ /dev/null @@ -1,30 +0,0 @@ -addSql('CREATE TABLE custom_invoice_template (id INT AUTO_INCREMENT NOT NULL, bid_id INT NOT NULL, submitter_id INT NOT NULL, name VARCHAR(255) NOT NULL, is_public TINYINT(1) NOT NULL, code LONGTEXT NOT NULL, INDEX IDX_CUSTOM_INV_TPL_BID (bid_id), INDEX IDX_CUSTOM_INV_TPL_SUBMITTER (submitter_id), PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8mb4 COLLATE `utf8mb4_unicode_ci` ENGINE = InnoDB'); - $this->addSql('ALTER TABLE custom_invoice_template ADD CONSTRAINT FK_CUSTOM_INV_TPL_BID FOREIGN KEY (bid_id) REFERENCES business (id)'); - $this->addSql('ALTER TABLE custom_invoice_template ADD CONSTRAINT FK_CUSTOM_INV_TPL_SUBMITTER FOREIGN KEY (submitter_id) REFERENCES `user` (id)'); - } - - public function down(Schema $schema): void - { - $this->addSql('ALTER TABLE custom_invoice_template DROP FOREIGN KEY FK_CUSTOM_INV_TPL_BID'); - $this->addSql('ALTER TABLE custom_invoice_template DROP FOREIGN KEY FK_CUSTOM_INV_TPL_SUBMITTER'); - $this->addSql('DROP TABLE custom_invoice_template'); - } -} \ No newline at end of file diff --git a/hesabixCore/migrations/Version20250806183700.php b/hesabixCore/migrations/Version20250811113332.php similarity index 64% rename from hesabixCore/migrations/Version20250806183700.php rename to hesabixCore/migrations/Version20250811113332.php index 7e7d4d4..b46c836 100644 --- a/hesabixCore/migrations/Version20250806183700.php +++ b/hesabixCore/migrations/Version20250811113332.php @@ -10,22 +10,26 @@ use Doctrine\Migrations\AbstractMigration; /** * Auto-generated Migration: Please modify to your needs! */ -final class Version20250806183700 extends AbstractMigration +final class Version20250811113332 extends AbstractMigration { public function getDescription(): string { - return 'Add warehouseManager field to permission table'; + return ''; } 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'); + $this->addSql(<<<'SQL' + ALTER TABLE person ADD require_two_step TINYINT(1) DEFAULT NULL + SQL); } 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'); + $this->addSql(<<<'SQL' + ALTER TABLE person DROP require_two_step + SQL); } } diff --git a/hesabixCore/src/Cog/PersonService.php b/hesabixCore/src/Cog/PersonService.php index 61c0ecd..7895d6c 100644 --- a/hesabixCore/src/Cog/PersonService.php +++ b/hesabixCore/src/Cog/PersonService.php @@ -288,6 +288,10 @@ class PersonService if (isset($params['shenasemeli'])) $person->setShenasemeli($params['shenasemeli']); if (isset($params['company'])) $person->setCompany($params['company']); if (isset($params['tags'])) $person->setTags($params['tags']); + if (isset($params['requireTwoStep'])) { + error_log("Setting requireTwoStep: " . var_export($params['requireTwoStep'], true)); + $person->setRequireTwoStep((bool)$params['requireTwoStep']); + } if (array_key_exists('prelabel', $params)) { if ($params['prelabel'] != '') { $prelabel = $em->getRepository(\App\Entity\PersonPrelabel::class)->findOneBy(['label' => $params['prelabel']]); diff --git a/hesabixCore/src/Controller/SellController.php b/hesabixCore/src/Controller/SellController.php index 07067a0..e9dbf80 100644 --- a/hesabixCore/src/Controller/SellController.php +++ b/hesabixCore/src/Controller/SellController.php @@ -324,7 +324,8 @@ class SellController extends AbstractController // Two-step approval: اگر پرمیشن کسبوکار تأیید دو مرحلهای فروش را الزامی کرده باشد $permission = $entityManager->getRepository(\App\Entity\Permission::class)->findOneBy(['bid' => $acc['bid'], 'user' => $acc['user']]); - if ($permission && $permission->isRequireTwoStepSell()) { + $personRequire = $person && method_exists($person, 'isRequireTwoStep') ? (bool)$person->isRequireTwoStep() : false; + if (($permission && $permission->isRequireTwoStepSell()) || $personRequire) { $doc->setStatus('pending_approval'); } else { $doc->setStatus('approved'); @@ -1320,7 +1321,8 @@ class SellController extends AbstractController // Two-step approval برای دریافت/پرداخت $permission = $entityManager->getRepository(\App\Entity\Permission::class)->findOneBy(['bid' => $acc['bid'], 'user' => $acc['user']]); - if ($permission && $permission->isRequireTwoStepPayment()) { + $personRequire = $person && method_exists($person, 'isRequireTwoStep') ? (bool)$person->isRequireTwoStep() : false; + if (($permission && $permission->isRequireTwoStepPayment()) || $personRequire) { $paymentDoc->setStatus('pending_approval'); } else { $paymentDoc->setStatus('approved'); diff --git a/hesabixCore/src/Controller/StoreroomController.php b/hesabixCore/src/Controller/StoreroomController.php index 911547f..673cad1 100644 --- a/hesabixCore/src/Controller/StoreroomController.php +++ b/hesabixCore/src/Controller/StoreroomController.php @@ -576,7 +576,8 @@ class StoreroomController extends AbstractController $entityManager->flush(); // اگر تأیید دو مرحلهای حواله فعال باشد، وضعیت را pending_approval بگذاریم $permission = $entityManager->getRepository(\App\Entity\Permission::class)->findOneBy(['bid' => $acc['bid'], 'user' => $acc['user']]); - if ($permission && $permission->isRequireTwoStepStore()) { + $personRequire = $person && method_exists($person, 'isRequireTwoStep') ? (bool)$person->isRequireTwoStep() : false; + if (($permission && $permission->isRequireTwoStepStore()) || $personRequire) { $ticket->setStatus('pending_approval'); $entityManager->persist($ticket); $entityManager->flush(); diff --git a/hesabixCore/src/Entity/Person.php b/hesabixCore/src/Entity/Person.php index d2733ab..19ac6cb 100644 --- a/hesabixCore/src/Entity/Person.php +++ b/hesabixCore/src/Entity/Person.php @@ -161,6 +161,9 @@ class Person #[ORM\Column(type: Types::TEXT, nullable: true)] private ?string $tags = null; + #[ORM\Column(nullable: true)] + private ?bool $requireTwoStep = null; + public function __construct() { $this->hesabdariRows = new ArrayCollection(); @@ -913,4 +916,15 @@ class Person $this->tags = $tags; return $this; } + + public function isRequireTwoStep(): ?bool + { + return $this->requireTwoStep; + } + + public function setRequireTwoStep(?bool $requireTwoStep): self + { + $this->requireTwoStep = $requireTwoStep; + return $this; + } } diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowCreateDialog.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowCreateDialog.vue new file mode 100644 index 0000000..e13d861 --- /dev/null +++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowCreateDialog.vue @@ -0,0 +1,306 @@ + + + + + mdi-plus + پرونده واردات جدید + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + لغو + + ایجاد + + + + + + + + + diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowCustoms.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowCustoms.vue new file mode 100644 index 0000000..f3208ce --- /dev/null +++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowCustoms.vue @@ -0,0 +1,423 @@ + + + + + اطلاعات ترخیص گمرکی + + افزودن اطلاعات ترخیص + + + + + + + {{ formatNumber(item.totalCustomsCharges) }} + ریال + + + + + + + + + + + + + + + {{ editingCustoms ? 'ویرایش اطلاعات ترخیص' : 'افزودن اطلاعات ترخیص جدید' }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + لغو + + {{ editingCustoms ? 'ویرایش' : 'افزودن' }} + + + + + + + + + + + \ No newline at end of file diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowDocuments.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowDocuments.vue new file mode 100644 index 0000000..5f023c7 --- /dev/null +++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowDocuments.vue @@ -0,0 +1,424 @@ + + + + + مدیریت اسناد + + افزودن سند + + + + + + + {{ getTypeText(item.type) }} + + + + + + {{ getFileIcon(item.fileType) }} + {{ item.fileName || '-' }} + + + + + {{ formatFileSize(item.fileSize) }} + + + + + + + + + + + + + + + {{ editingDocument ? 'ویرایش سند' : 'افزودن سند جدید' }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + لغو + + {{ editingDocument ? 'ویرایش' : 'افزودن' }} + + + + + + + + + + + + + + diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowItems.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowItems.vue new file mode 100644 index 0000000..f33e97b --- /dev/null +++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowItems.vue @@ -0,0 +1,484 @@ + + + + + آیتمهای وارداتی + + افزودن آیتم + + + + + + + {{ formatNumber(item.unitPrice) }} + {{ getCurrency(item) }} + + + + + + {{ formatNumber(item.totalPrice) }} + {{ getCurrency(item) }} + + + + + + + + + + + + + + + {{ editingItem ? 'ویرایش آیتم' : 'افزودن آیتم جدید' }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + لغو + + {{ editingItem ? 'ویرایش' : 'افزودن' }} + + + + + + + + + + حذف آیتم + + آیا از حذف آیتم "{{ selectedItem?.name }}" اطمینان دارید؟ + + + + لغو + حذف + + + + + + + + + + + + diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowPayments.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowPayments.vue new file mode 100644 index 0000000..4db9b96 --- /dev/null +++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowPayments.vue @@ -0,0 +1,548 @@ + + + + + پرداختها + + افزودن پرداخت + + + + + + + {{ getTypeText(item.type) }} + + + + + + {{ formatNumber(item.amount) }} + {{ item.currency }} + + + + + + {{ formatNumber(item.amountIRR) }} + ریال + + + + + + {{ getStatusText(item.status) }} + + + + + {{ formatDate(item.paymentDate) }} + + + + + + + + + + + + + + {{ editingPayment ? 'ویرایش پرداخت' : 'افزودن پرداخت جدید' }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + لغو + + {{ editingPayment ? 'ویرایش' : 'افزودن' }} + + + + + + + + + + حذف پرداخت + + آیا از حذف این پرداخت اطمینان دارید؟ + + + + لغو + حذف + + + + + + + + + + + + diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowShipping.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowShipping.vue new file mode 100644 index 0000000..6c9cbfd --- /dev/null +++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowShipping.vue @@ -0,0 +1,394 @@ + + + + + اطلاعات حمل و نقل + + افزودن اطلاعات حمل + + + + + + + {{ getTypeText(item.type) }} + + + + + + + + + + + + + + + {{ editingShipping ? 'ویرایش اطلاعات حمل' : 'افزودن اطلاعات حمل جدید' }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + لغو + + {{ editingShipping ? 'ویرایش' : 'افزودن' }} + + + + + + + + + + + + + + diff --git a/webUI/src/components/plugins/import-workflow/ImportWorkflowStages.vue b/webUI/src/components/plugins/import-workflow/ImportWorkflowStages.vue new file mode 100644 index 0000000..62454ea --- /dev/null +++ b/webUI/src/components/plugins/import-workflow/ImportWorkflowStages.vue @@ -0,0 +1,438 @@ + + + + + مراحل واردات + + افزودن مرحله + + + + + + + {{ getStageIcon(stage.stage) }} + + + + {{ getStageText(stage.stage) }} + + + + {{ getStatusText(stage.status) }} + + + تاریخ شروع: {{ formatDate(stage.startDate) }} + + + تاریخ پایان: {{ formatDate(stage.endDate) }} + + + + + ویرایش + + + + + + + + + + {{ getStageIcon(item.stage) }} + {{ getStageText(item.stage) }} + + + + + + {{ getStatusText(item.status) }} + + + + + + + + + + + + + + + {{ editingStage ? 'ویرایش مرحله' : 'افزودن مرحله جدید' }} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + لغو + + {{ editingStage ? 'ویرایش' : 'افزودن' }} + + + + + + + + + + + + + + diff --git a/webUI/src/router/index.ts b/webUI/src/router/index.ts index 389b00c..1bd05b2 100755 --- a/webUI/src/router/index.ts +++ b/webUI/src/router/index.ts @@ -1061,20 +1061,20 @@ const router = createRouter({ import('../views/acc/inquiry/panel.vue'), }, { - path: 'import-workflow/list', + path: 'plugins/import-workflow/list', name: 'import_workflow_list', component: () => - import('../views/ImportWorkflow/ImportWorkflowList.vue'), + import('../views/acc/plugins/import-workflow/list.vue'), meta: { 'title': 'مدیریت واردات کالا', 'login': true, } }, { - path: 'import-workflow/:id', + path: 'plugins/import-workflow/:id', name: 'import_workflow_detail', component: () => - import('../views/ImportWorkflow/ImportWorkflowDetail.vue'), + import('../views/acc/plugins/import-workflow/view.vue'), meta: { 'title': 'جزئیات پرونده واردات', 'login': true, diff --git a/webUI/src/views/acc/App.vue b/webUI/src/views/acc/App.vue index b1c6a57..80b531e 100755 --- a/webUI/src/views/acc/App.vue +++ b/webUI/src/views/acc/App.vue @@ -216,7 +216,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 }, + { path: '/acc/plugins/import-workflow', key: 'I', label: 'مدیریت واردات کالا', ctrl: true, shift: true, permission: () => this.permissions.importWorkflow }, ]; }, restorePermissions(shortcuts) { @@ -807,20 +807,21 @@ export default { {{ $t('drawer.services') }} - + - + لیست پروندههای واردات + {{ getShortcutKey('/acc/plugins/import-workflow/list') }} - + diff --git a/webUI/src/views/acc/persons/card.vue b/webUI/src/views/acc/persons/card.vue index 6fa709a..f077a48 100755 --- a/webUI/src/views/acc/persons/card.vue +++ b/webUI/src/views/acc/persons/card.vue @@ -11,6 +11,9 @@ {{ $t('dialog.banks_accounts') }} + + ویرایش شخص + @@ -91,6 +94,94 @@ + + + + + ویرایش شخص + + + mdi-close + + + + + + + + + + + + + + + + + + + + + + + + + + + تأیید دو مرحلهای + + + + اگر این گزینه فعال باشد، تمام فاکتورها، حوالههای انبار و اسناد مالی مرتبط با این شخص نیاز به تأیید دو مرحلهای خواهند داشت. + + + + + + + + + انصراف + + + ذخیره + + + + + @@ -151,6 +242,21 @@ selectedPerson.address || '-' }} {{ $t('pages.person.description') }}: {{ selectedPerson.des || '-' }} + @@ -179,6 +285,13 @@ $filters.formatNumber(selectedPerson.bd) || '-' }} {{ $t('pages.person_card.accounting_balance') }}: {{ $filters.formatNumber(selectedPerson.balance) || '-' }} + + + تأیید دو مرحلهای: + + {{ selectedPerson.requireTwoStep ? 'فعال' : 'غیرفعال' }} + + @@ -259,10 +372,22 @@ export default { searchValue: '', listPersons: [], itemsSelected: [], - selectedPerson: { accounts: [], balance: 0, bs: 0, bd: 0 }, + selectedPerson: { accounts: [], balance: 0, bs: 0, bd: 0, requireTwoStep: false }, items: [], loading: ref(false), dialog: false, + editPersonDialog: false, + editPersonFormValid: false, + saveLoading: false, + editPersonData: { + nikename: '', + name: '', + mobile: '', + tel: '', + address: '', + des: '', + requireTwoStep: false + }, debounceTimeout: null, // برای مدیریت debounce headers: [ { title: this.$t('dialog.operation'), key: "operation", align: "center", sortable: false }, @@ -338,17 +463,50 @@ export default { try { const personResponse = await axios.post('/api/person/info/' + id); this.selectedPerson = personResponse.data; + // پر کردن فرم ویرایش با اطلاعات فعلی شخص + this.editPersonData = { + nikename: this.selectedPerson.nikename || '', + name: this.selectedPerson.name || '', + mobile: this.selectedPerson.mobile || '', + tel: this.selectedPerson.tel || '', + address: this.selectedPerson.address || '', + des: this.selectedPerson.des || '', + requireTwoStep: this.selectedPerson.requireTwoStep || false + }; const rowsResponse = await axios.post('/api/accounting/rows/search', { type: 'person', id }); this.items = rowsResponse.data; } catch (error) { console.error('Load person error:', error); - this.selectedPerson = { accounts: [], balance: 0, bs: 0, bd: 0 }; + this.selectedPerson = { accounts: [], balance: 0, bs: 0, bd: 0, requireTwoStep: false }; this.items = []; } finally { this.loading = false; } }, + async savePersonChanges() { + if (!this.selectedPerson || !this.selectedPerson.code) { + this.snackbar = { show: true, text: 'شخص انتخاب نشده است', color: 'error' }; + return; + } + this.saveLoading = true; + try { + const response = await axios.post('/api/person/mod/' + this.selectedPerson.code, this.editPersonData); + if (response.data.Success) { + this.snackbar = { show: true, text: 'اطلاعات شخص با موفقیت بروزرسانی شد', color: 'success' }; + this.editPersonDialog = false; + // بروزرسانی اطلاعات شخص + await this.loadPerson(this.selectedPerson.code); + } else { + this.snackbar = { show: true, text: 'خطا در بروزرسانی اطلاعات شخص', color: 'error' }; + } + } catch (error) { + console.error('Save person error:', error); + this.snackbar = { show: true, text: 'خطا در بروزرسانی اطلاعات شخص', color: 'error' }; + } finally { + this.saveLoading = false; + } + }, async excellOutput(allItems = true) { if (!allItems && this.itemsSelected.length === 0) { Swal.fire({ text: this.$t('pages.person_card.no_items_selected'), icon: 'info', confirmButtonText: this.$t('dialog.confirm') }); @@ -429,6 +587,16 @@ export default { return labels[type] || type; }, }, + computed: { + snackbar: { + get() { + return this.$store.state.snackbar; + }, + set(value) { + this.$store.commit('setSnackbar', value); + } + } + } }; diff --git a/webUI/src/views/acc/persons/insert.vue b/webUI/src/views/acc/persons/insert.vue index d9bda3f..2f03d83 100755 --- a/webUI/src/views/acc/persons/insert.vue +++ b/webUI/src/views/acc/persons/insert.vue @@ -65,6 +65,23 @@ + + + + تأیید دو مرحلهای + + + + اگر این گزینه فعال باشد، تمام فاکتورها، حوالههای انبار و اسناد مالی مرتبط با این شخص نیاز به تأیید دو مرحلهای خواهند داشت. + + @@ -287,7 +304,8 @@ export default { types: [], accounts: [], prelabel: ref(null), - speedAccess: false + speedAccess: false, + requireTwoStep: false }, snackbar: { show: false, @@ -404,6 +422,8 @@ export default { if (canSubmit) { this.loading = true; try { + console.log('Saving person data:', this.person); + console.log('requireTwoStep value:', this.person.requireTwoStep); const response = await axios.post('/api/person/mod/' + this.person.code, this.person); this.loading = false; if (response.data && response.data.result === 2) { diff --git a/webUI/src/views/acc/persons/receive/list.vue b/webUI/src/views/acc/persons/receive/list.vue index 63b706d..b518bce 100755 --- a/webUI/src/views/acc/persons/receive/list.vue +++ b/webUI/src/views/acc/persons/receive/list.vue @@ -35,6 +35,13 @@ + + + + mdi-check-decagram + + + @@ -434,6 +441,28 @@ const updateSelectedSum = () => { } }; +const approveSelectedPayments = async () => { + if (selectedItems.value.length === 0) { + Swal.fire({ text: 'هیچ آیتمی انتخاب نشده است.', icon: 'warning', confirmButtonText: 'قبول' }); + return; + } + const res = await Swal.fire({ title: 'تایید پرداختها', text: 'پرداختهای انتخابی تایید خواهند شد.', icon: 'question', showCancelButton: true, confirmButtonText: 'بله', cancelButtonText: 'خیر' }); + if (!res.isConfirmed) return; + loading.value = true; + try { + for (const it of selectedItems.value) { + await axios.post(`/api/sell/payment/approve/${it.code}`); + } + Swal.fire({ text: 'پرداختها تایید شدند.', icon: 'success', confirmButtonText: 'قبول' }); + selectedItems.value = []; + await loadData(); + } catch (e) { + Swal.fire({ text: 'خطا در تایید پرداختها', icon: 'error', confirmButtonText: 'قبول' }); + } finally { + loading.value = false; + } +}; + const print = async (allItems = true) => { if (!allItems && selectedItems.value.length === 0) { Swal.fire({ diff --git a/webUI/src/views/acc/plugins/import-workflow/list.vue b/webUI/src/views/acc/plugins/import-workflow/list.vue new file mode 100644 index 0000000..449bbc0 --- /dev/null +++ b/webUI/src/views/acc/plugins/import-workflow/list.vue @@ -0,0 +1,681 @@ + + + + + + + + + mdi-import + mdi-import + + + + + {{ stats.totalWorkflows || 0 }} + + کل پروندهها + + + + + + + mdi-file-document-outline + mdi-file-document-outline + + + + + {{ stats.draftWorkflows || 0 }} + + پیشنویس + + + + + + + mdi-progress-clock + mdi-progress-clock + + + + + {{ stats.processingWorkflows || 0 }} + + در حال پردازش + + + + + + + mdi-check-circle + mdi-check-circle + + + + + {{ stats.completedWorkflows || 0 }} + + تکمیل شده + + + + + + + + + + + + + + + + پرونده واردات جدید + + + + + + + + + + + + + + پرونده واردات جدید + + + + + + + + {{ getStatusText(item.status) }} + + + + + + {{ formatNumber(item.totalAmount) }} + {{ item.currency }} + + + + + {{ formatDate(item.dateSubmit) }} + + + + + + + + + + + mdi-eye + + مشاهده پرونده + + + + mdi-pencil + + ویرایش پرونده + + + + mdi-delete + + حذف پرونده + + + + + + + + + + + + + + + + + حذف پرونده واردات + + آیا از حذف پرونده واردات "{{ selectedWorkflow?.title }}" اطمینان دارید؟ + + + + لغو + حذف + + + + + + + + + {{ snackbarColor === 'success' ? 'mdi-check-circle' : 'mdi-alert-circle' }} + + {{ snackbarText }} + + + + mdi-close + + + + + + + + + + + diff --git a/webUI/src/views/acc/plugins/import-workflow/view.vue b/webUI/src/views/acc/plugins/import-workflow/view.vue new file mode 100644 index 0000000..afb9a00 --- /dev/null +++ b/webUI/src/views/acc/plugins/import-workflow/view.vue @@ -0,0 +1,820 @@ + + + + + + + + + + + mdi-import + {{ workflow?.title || 'جزئیات پرونده واردات' }} + + + + {{ getStatusText(workflow?.status) }} + + + {{ editMode ? 'لغو ویرایش' : 'ویرایش' }} + + + ایجاد حواله ورود از پرونده + + + + + + + + + + + + + + + + + + + اطلاعات کلی + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ذخیره تغییرات + + + + + + + + + + نام تامین کننده: + {{ workflow.supplierName || '-' }} + + + + + کشور تامین کننده: + {{ workflow.supplierCountry || '-' }} + + + + + + + تلفن تامین کننده: + {{ workflow.supplierPhone || '-' }} + + + + + ایمیل تامین کننده: + {{ workflow.supplierEmail || '-' }} + + + + + + + آدرس تامین کننده: + {{ workflow.supplierAddress || '-' }} + + + + + + + مبلغ کل: + {{ formatMoney(workflow.totalAmount) }} {{ workflow.currency }} + + + + + نرخ تبدیل: + {{ formatMoney(workflow.exchangeRate) }} + + + + + مبلغ کل (ریال): + {{ formatMoney(workflow.totalAmountIRR) }} + + + + + + + توضیحات: + {{ workflow.description || '-' }} + + + + + + + + + + + اطلاعات سیستمی + + + کد پرونده: + {{ workflow.code }} + + + تاریخ ثبت: + {{ formatDate(workflow.dateSubmit) }} + + + ثبت کننده: + {{ workflow.submitter }} + + + + + + + + + + + + آیتمها ({{ workflow.items?.length || 0 }}) + پرداختها ({{ workflow.payments?.length || 0 }}) + اسناد ({{ workflow.documents?.length || 0 }}) + مراحل ({{ workflow.stages?.length || 0 }}) + حمل و نقل ({{ workflow.shipping?.length || 0 }}) + ترخیص ({{ workflow.customs?.length || 0 }}) + حوالههای مرتبط + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ item.code }} + + + + {{ ticketStatusLabel(item.status) }} + + + + + مشاهده + + + + + mdi-dots-vertical + + + + + {{ st.title }} + + + + + + + + + + + + + + + + + + ایجاد حواله ورود به انبار + + + + + + + + + جستجو + + + + + + + + انصراف + ایجاد حواله + + + + + + + + + + + + + + diff --git a/webUI/src/views/acc/sell/list.vue b/webUI/src/views/acc/sell/list.vue index d3e2f0b..1b3f49b 100755 --- a/webUI/src/views/acc/sell/list.vue +++ b/webUI/src/views/acc/sell/list.vue @@ -39,6 +39,12 @@ + وضعیت تایید + + + + + {{ $t('dialog.change_labels') }} @@ -419,6 +425,29 @@ export default defineComponent({ }, }, methods: { + approveSelectedInvoices() { + if (this.itemsSelected.length === 0) { + Swal.fire({ text: 'هیچ موردی انتخاب نشده است.', icon: 'warning', confirmButtonText: 'قبول' }); + return; + } + Swal.fire({ title: 'تایید فاکتورهای انتخابی', text: 'فاکتورهای انتخابشده تایید خواهند شد.', icon: 'question', showCancelButton: true, confirmButtonText: 'بله', cancelButtonText: 'خیر' }) + .then(async (r) => { + if (!r.isConfirmed) return; + this.loading = true; + try { + for (const code of this.itemsSelected) { + await axios.post(`/api/sell/approve/${code}`); + } + Swal.fire({ text: 'فاکتورها تایید شدند.', icon: 'success', confirmButtonText: 'قبول' }); + this.itemsSelected = []; + this.loadData(); + } catch (e) { + Swal.fire({ text: 'خطا در تایید فاکتورها', icon: 'error', confirmButtonText: 'قبول' }); + } finally { + this.loading = false; + } + }); + }, isPluginActive(pluginCode) { return this.plugins && this.plugins[pluginCode] !== undefined; }, diff --git a/webUI/src/views/acc/sell/viewInvoice.vue b/webUI/src/views/acc/sell/viewInvoice.vue index aca257d..b1bb5bc 100755 --- a/webUI/src/views/acc/sell/viewInvoice.vue +++ b/webUI/src/views/acc/sell/viewInvoice.vue @@ -1,4 +1,4 @@ - @@ -150,6 +198,7 @@ onMounted(() => { @click="printInvoice" color="primary" icon="mdi-printer" + :disabled="!canPrint" /> @@ -293,6 +342,53 @@ onMounted(() => { + + + + mdi-paperclip + پیوستها + + + + + + آپلود + + + + + + {{ item.filename }} + + + +