bug fix in open balance

This commit is contained in:
Hesabix 2025-08-21 15:29:02 +00:00
parent da074d2e89
commit f609c4176f
2 changed files with 314 additions and 42 deletions

View file

@ -136,6 +136,37 @@ class OpenbalanceController extends AbstractController
if (!$acc)
throw $this->createAccessDeniedException();
// بررسی مجوز تغییر تراز افتتاحیه
$years = $entityManagerInterface->getRepository(\App\Entity\Year::class)->findBy([
'bid' => $acc['bid']
], ['start' => 'ASC']);
$currentYear = $acc['year'];
$isFirstYear = false;
$hasMultipleYears = count($years) > 1;
// بررسی اینکه آیا سال فعلی اولین سال مالی است
if (count($years) > 0) {
$firstYear = $years[0];
$isFirstYear = ($currentYear->getId() === $firstYear->getId());
}
$canModify = $isFirstYear && !$hasMultipleYears;
if (!$canModify) {
$message = '';
if ($hasMultipleYears && !$isFirstYear) {
$message = 'تراز افتتاحیه فقط مختص سال مالی اول است. برای سال‌های بعدی از بستن سال مالی استفاده کنید.';
} elseif ($hasMultipleYears && $isFirstYear) {
$message = 'این کسب و کار دارای چندین سال مالی است. تراز افتتاحیه فقط در سال اول قابل تغییر است.';
}
return $this->json([
'result' => 0,
'message' => $message
]);
}
$params = [];
if ($content = $request->getContent()) {
$params = json_decode($content, true);
@ -157,7 +188,7 @@ class OpenbalanceController extends AbstractController
$doc->setSubmitter($this->getUser());
$doc->setYear($acc['year']);
$doc->setDes('سند افتتاحیه');
$doc->setDate($jdate->jdate('Y/n/d', time()));
$doc->setDate($jdate->jdate('Y/n/d', $acc['year']->getStart()));
$doc->setType('open_balance');
$doc->setCode($provider->getAccountingCode($acc['bid'],'accounting'));
$entityManagerInterface->persist($doc);
@ -233,7 +264,7 @@ class OpenbalanceController extends AbstractController
$doc->setSubmitter($this->getUser());
$doc->setYear($acc['year']);
$doc->setDes('سند افتتاحیه');
$doc->setDate($jdate->jdate('Y/n/d', time()));
$doc->setDate($jdate->jdate('Y/n/d', $acc['year']->getStart()));
$doc->setType('open_balance');
$doc->setCode($provider->getAccountingCode($acc['bid'],'accounting'));
$entityManagerInterface->persist($doc);
@ -309,7 +340,7 @@ class OpenbalanceController extends AbstractController
$doc->setSubmitter($this->getUser());
$doc->setYear($acc['year']);
$doc->setDes('سند افتتاحیه');
$doc->setDate($jdate->jdate('Y/n/d', time()));
$doc->setDate($jdate->jdate('Y/n/d', $acc['year']->getStart()));
$doc->setType('open_balance');
$doc->setCode($provider->getAccountingCode($acc['bid'],'accounting'));
$entityManagerInterface->persist($doc);
@ -385,7 +416,7 @@ class OpenbalanceController extends AbstractController
$doc->setSubmitter($this->getUser());
$doc->setYear($acc['year']);
$doc->setDes('سند افتتاحیه');
$doc->setDate($jdate->jdate('Y/n/d', time()));
$doc->setDate($jdate->jdate('Y/n/d', $acc['year']->getStart()));
$doc->setType('open_balance');
$doc->setCode($provider->getAccountingCode($acc['bid'],'accounting'));
$entityManagerInterface->persist($doc);
@ -468,7 +499,7 @@ class OpenbalanceController extends AbstractController
$doc->setSubmitter($this->getUser());
$doc->setYear($acc['year']);
$doc->setDes('سند افتتاحیه');
$doc->setDate($jdate->jdate('Y/n/d', time()));
$doc->setDate($jdate->jdate('Y/n/d', $acc['year']->getStart()));
$doc->setType('open_balance');
$doc->setCode($provider->getAccountingCode($acc['bid'],'accounting'));
$entityManagerInterface->persist($doc);
@ -533,4 +564,93 @@ class OpenbalanceController extends AbstractController
$entityManagerInterface->flush();
return $this->json($extractor->operationSuccess());
}
#[Route('/api/openbalance/check-permission', name: 'app_openbalance_check_permission')]
public function app_openbalance_check_permission(Access $access, EntityManagerInterface $entityManagerInterface, Extractor $extractor): Response
{
$acc = $access->hasRole('accounting');
if (!$acc)
throw $this->createAccessDeniedException();
// بررسی تعداد سال‌های مالی کسب و کار
$years = $entityManagerInterface->getRepository(\App\Entity\Year::class)->findBy([
'bid' => $acc['bid']
], ['start' => 'ASC']);
$currentYear = $acc['year'];
$isFirstYear = false;
$hasMultipleYears = count($years) > 1;
// بررسی اینکه آیا سال فعلی اولین سال مالی است
if (count($years) > 0) {
$firstYear = $years[0];
$isFirstYear = ($currentYear->getId() === $firstYear->getId());
}
// بررسی اینکه آیا سند افتتاحیه قبلاً ایجاد شده
$existingDoc = $entityManagerInterface->getRepository(HesabdariDoc::class)->findOneBy([
'year' => $currentYear,
'bid' => $acc['bid'],
'type' => 'open_balance',
'money' => $acc['money']
]);
$canModify = $isFirstYear && !$hasMultipleYears;
$message = '';
if ($hasMultipleYears && !$isFirstYear) {
$message = 'تراز افتتاحیه فقط مختص سال مالی اول است. برای سال‌های بعدی از بستن سال مالی استفاده کنید.';
} elseif ($hasMultipleYears && $isFirstYear) {
$message = 'این کسب و کار دارای چندین سال مالی است. تراز افتتاحیه فقط در سال اول قابل تغییر است.';
} elseif ($existingDoc) {
$message = 'سند افتتاحیه قبلاً ایجاد شده است.';
}
return $this->json([
'canModify' => $canModify,
'isFirstYear' => $isFirstYear,
'hasMultipleYears' => $hasMultipleYears,
'existingDoc' => $existingDoc ? true : false,
'message' => $message,
'yearsCount' => count($years)
]);
}
/**
* بررسی مجوز تغییر تراز افتتاحیه
*/
private function checkOpeningBalancePermission(EntityManagerInterface $entityManagerInterface, array $acc): array
{
// بررسی تعداد سال‌های مالی کسب و کار
$years = $entityManagerInterface->getRepository(\App\Entity\Year::class)->findBy([
'bid' => $acc['bid']
], ['start' => 'ASC']);
$currentYear = $acc['year'];
$isFirstYear = false;
$hasMultipleYears = count($years) > 1;
// بررسی اینکه آیا سال فعلی اولین سال مالی است
if (count($years) > 0) {
$firstYear = $years[0];
$isFirstYear = ($currentYear->getId() === $firstYear->getId());
}
$canModify = $isFirstYear && !$hasMultipleYears;
$message = '';
if ($hasMultipleYears && !$isFirstYear) {
$message = 'تراز افتتاحیه فقط مختص سال مالی اول است. برای سال‌های بعدی از بستن سال مالی استفاده کنید.';
} elseif ($hasMultipleYears && $isFirstYear) {
$message = 'این کسب و کار دارای چندین سال مالی است. تراز افتتاحیه فقط در سال اول قابل تغییر است.';
}
return [
'canModify' => $canModify,
'message' => $message,
'isFirstYear' => $isFirstYear,
'hasMultipleYears' => $hasMultipleYears,
'yearsCount' => count($years)
];
}
}

View file

@ -12,6 +12,9 @@
</v-toolbar>
<v-container>
<v-row class="pa-1">
<v-col v-if="!permission.canModify" cols="12" sm="12" md="12">
<v-alert :title="'محدودیت دسترسی'" :text="permission.message" type="warning"></v-alert>
</v-col>
<v-col v-if="sums.degSum != sums.shareSum" cols="12" sm="12" md="12">
<v-alert :title="$t('dialog.error')" :text="$t('dialog.openbalance_notvalid')" type="warning"></v-alert>
</v-col>
@ -82,7 +85,7 @@
</v-tooltip>
</template>
<v-spacer></v-spacer>
<v-btn :loading="loading" @click="saveBanks()" icon="" color="green">
<v-btn :loading="loading" :disabled="!permission.canModify" @click="saveBanks()" icon="" color="green">
<v-tooltip activator="parent" :text="$t('dialog.save')" location="bottom" />
<v-icon icon="mdi-content-save"></v-icon>
</v-btn>
@ -92,7 +95,7 @@
<v-row>
<v-col v-for="item in data.banks" :key="item.info.id" cols="12" sm="6" md="4">
<div class="form-floating mb-3">
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" />
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" :disabled="!permission.canModify" />
<label for="floatingInput">{{ item.info.name }} ({{ $filters.getActiveMoney().symbol }}) </label>
</div>
</v-col>
@ -111,7 +114,7 @@
</v-tooltip>
</template>
<v-spacer></v-spacer>
<v-btn :loading="loading" @click="saveCashdesks()" icon="" color="green">
<v-btn :loading="loading" :disabled="!permission.canModify" @click="saveCashdesks()" icon="" color="green">
<v-tooltip activator="parent" :text="$t('dialog.save')" location="bottom" />
<v-icon icon="mdi-content-save"></v-icon>
</v-btn>
@ -121,7 +124,7 @@
<v-row>
<v-col v-for="item in data.cashdesks" :key="item.info.id" cols="12" sm="6" md="4">
<div class="form-floating mb-3">
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" />
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" :disabled="!permission.canModify" />
<label for="floatingInput">{{ item.info.name }} ({{ $filters.getActiveMoney().symbol }}) </label>
</div>
</v-col>
@ -140,7 +143,7 @@
</v-tooltip>
</template>
<v-spacer></v-spacer>
<v-btn :loading="loading" @click="saveSalarys()" icon="" color="green">
<v-btn :loading="loading" :disabled="!permission.canModify" @click="saveSalarys()" icon="" color="green">
<v-tooltip activator="parent" :text="$t('dialog.save')" location="bottom" />
<v-icon icon="mdi-content-save"></v-icon>
</v-btn>
@ -150,7 +153,7 @@
<v-row>
<v-col v-for="item in data.salarys" :key="item.info.id" cols="12" sm="6" md="4">
<div class="form-floating mb-3">
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" />
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" :disabled="!permission.canModify" />
<label for="floatingInput">{{ item.info.name }} ({{ $filters.getActiveMoney().symbol }}) </label>
</div>
</v-col>
@ -169,7 +172,7 @@
</v-tooltip>
</template>
<v-spacer></v-spacer>
<v-btn :loading="loading" @click="saveShareholders()" icon="" color="green">
<v-btn :loading="loading" :disabled="!permission.canModify" @click="saveShareholders()" icon="" color="green">
<v-tooltip activator="parent" :text="$t('dialog.save')" location="bottom" />
<v-icon icon="mdi-content-save"></v-icon>
</v-btn>
@ -179,7 +182,7 @@
<v-row>
<v-col v-for="item in data.shareholders" :key="item.info.id" cols="12" sm="6" md="4">
<div class="form-floating mb-3">
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" />
<money3 v-bind="currencyConfig" min=0 class="form-control" v-model="item.openbalance" :disabled="!permission.canModify" />
<label for="floatingInput">{{ item.info.nikename }} ({{ $filters.getActiveMoney().symbol }}) </label>
</div>
</v-col>
@ -204,6 +207,7 @@
<v-btn
v-bind="props"
:loading="loading"
:disabled="!permission.canModify"
@click="saveInventory()"
color="success"
variant="text"
@ -240,7 +244,7 @@
</td>
<td class="text-center" style="width: 100px;">
<Hnumberinput
v-model="item.count"
v-model="item.count" :disabled="!permission.canModify"
density="compact"
hide-details
class="my-0"
@ -250,7 +254,7 @@
</td>
<td class="text-center" style="width: 120px;">
<Hnumberinput
v-model="item.price"
v-model="item.price" :disabled="!permission.canModify"
density="compact"
hide-details
class="my-0"
@ -310,7 +314,7 @@
<div class="d-flex justify-space-between mb-2">
<div style="width: 48%;">
<Hnumberinput
v-model="item.count"
v-model="item.count" :disabled="!permission.canModify"
density="compact"
label="تعداد"
hide-details
@ -321,7 +325,7 @@
</div>
<div style="width: 48%;">
<Hnumberinput
v-model="item.price"
v-model="item.price" :disabled="!permission.canModify"
density="compact"
label="قیمت واحد"
hide-details
@ -434,13 +438,31 @@ export default {
show: false,
text: '',
color: 'error'
},
permission: {
canModify: true,
message: '',
isFirstYear: false,
hasMultipleYears: false,
existingDoc: false,
yearsCount: 0
}
}
},
mounted() {
this.loadData();
this.checkPermission();
},
methods: {
checkPermission() {
axios.post('/api/openbalance/check-permission').then((response) => {
this.permission = response.data;
}).catch(error => {
console.error('Error checking permission:', error);
this.permission.canModify = false;
this.permission.message = 'خطا در بررسی مجوز';
});
},
loadData() {
this.sums.banks = 0;
this.sums.cashdesks = 0;
@ -509,35 +531,147 @@ export default {
},
saveBanks() {
this.loading = true;
axios.post('/api/openbalance/save/banks', this.data.banks).then((Response) => {
// ابتدا بررسی مجوز
axios.post('/api/openbalance/check-permission').then((permissionResponse) => {
if (!permissionResponse.data.canModify) {
this.loading = false;
this.snackbar.text = permissionResponse.data.message;
this.snackbar.color = 'error';
this.snackbar.show = true;
return;
}
// اگر مجوز داشت، ذخیره کن
axios.post('/api/openbalance/save/banks', this.data.banks).then((Response) => {
this.loading = false;
this.loadData();
this.sheet.banks = false;
this.snackbar.text = 'اطلاعات بانک‌ها با موفقیت ذخیره شد';
this.snackbar.color = 'success';
this.snackbar.show = true;
}).catch(error => {
this.loading = false;
this.snackbar.text = 'خطا در ذخیره اطلاعات';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error saving banks:', error);
});
}).catch(error => {
this.loading = false;
this.loadData();
this.sheet.banks = false;
})
this.snackbar.text = 'خطا در بررسی مجوز';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error checking permission:', error);
});
},
saveCashdesks() {
this.loading = true;
axios.post('/api/openbalance/save/cashdesks', this.data.cashdesks).then((Response) => {
// ابتدا بررسی مجوز
axios.post('/api/openbalance/check-permission').then((permissionResponse) => {
if (!permissionResponse.data.canModify) {
this.loading = false;
this.snackbar.text = permissionResponse.data.message;
this.snackbar.color = 'error';
this.snackbar.show = true;
return;
}
// اگر مجوز داشت، ذخیره کن
axios.post('/api/openbalance/save/cashdesks', this.data.cashdesks).then((Response) => {
this.loading = false;
this.loadData();
this.sheet.cashdesks = false;
this.snackbar.text = 'اطلاعات صندوق‌ها با موفقیت ذخیره شد';
this.snackbar.color = 'success';
this.snackbar.show = true;
}).catch(error => {
this.loading = false;
this.snackbar.text = 'خطا در ذخیره اطلاعات';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error saving cashdesks:', error);
});
}).catch(error => {
this.loading = false;
this.loadData();
this.sheet.cashdesks = false;
})
this.snackbar.text = 'خطا در بررسی مجوز';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error checking permission:', error);
});
},
saveSalarys() {
this.loading = true;
axios.post('/api/openbalance/save/salarys', this.data.salarys).then((Response) => {
// ابتدا بررسی مجوز
axios.post('/api/openbalance/check-permission').then((permissionResponse) => {
if (!permissionResponse.data.canModify) {
this.loading = false;
this.snackbar.text = permissionResponse.data.message;
this.snackbar.color = 'error';
this.snackbar.show = true;
return;
}
// اگر مجوز داشت، ذخیره کن
axios.post('/api/openbalance/save/salarys', this.data.salarys).then((Response) => {
this.loading = false;
this.loadData();
this.sheet.salarys = false;
this.snackbar.text = 'اطلاعات تنخواه‌گردان‌ها با موفقیت ذخیره شد';
this.snackbar.color = 'success';
this.snackbar.show = true;
}).catch(error => {
this.loading = false;
this.snackbar.text = 'خطا در ذخیره اطلاعات';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error saving salarys:', error);
});
}).catch(error => {
this.loading = false;
this.loadData();
this.sheet.salarys = false;
})
this.snackbar.text = 'خطا در بررسی مجوز';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error checking permission:', error);
});
},
saveShareholders() {
this.loading = true;
axios.post('/api/openbalance/save/shareholders', this.data.shareholders).then((Response) => {
// ابتدا بررسی مجوز
axios.post('/api/openbalance/check-permission').then((permissionResponse) => {
if (!permissionResponse.data.canModify) {
this.loading = false;
this.snackbar.text = permissionResponse.data.message;
this.snackbar.color = 'error';
this.snackbar.show = true;
return;
}
// اگر مجوز داشت، ذخیره کن
axios.post('/api/openbalance/save/shareholders', this.data.shareholders).then((Response) => {
this.loading = false;
this.loadData();
this.sheet.shareholders = false;
this.snackbar.text = 'اطلاعات سهام‌داران با موفقیت ذخیره شد';
this.snackbar.color = 'success';
this.snackbar.show = true;
}).catch(error => {
this.loading = false;
this.snackbar.text = 'خطا در ذخیره اطلاعات';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error saving shareholders:', error);
});
}).catch(error => {
this.loading = false;
this.loadData();
this.sheet.shareholders = false;
})
this.snackbar.text = 'خطا در بررسی مجوز';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error checking permission:', error);
});
},
calculateTotalPrice(item) {
item.totalPrice = parseFloat(item.count || 0) * parseFloat(item.price || 0);
@ -609,19 +743,37 @@ export default {
totalPrice: parseFloat(item.totalPrice)
}));
axios.post('/api/openbalance/save/commodities', commoditiesData).then((Response) => {
this.loading = false;
this.loadData();
this.sheet.inventory = false;
this.snackbar.text = this.$t('dialog.inventory.save_success');
this.snackbar.color = 'success';
this.snackbar.show = true;
// ابتدا بررسی مجوز
axios.post('/api/openbalance/check-permission').then((permissionResponse) => {
if (!permissionResponse.data.canModify) {
this.loading = false;
this.snackbar.text = permissionResponse.data.message;
this.snackbar.color = 'error';
this.snackbar.show = true;
return;
}
// اگر مجوز داشت، ذخیره کن
axios.post('/api/openbalance/save/commodities', commoditiesData).then((Response) => {
this.loading = false;
this.loadData();
this.sheet.inventory = false;
this.snackbar.text = 'اطلاعات موجودی کالا با موفقیت ذخیره شد';
this.snackbar.color = 'success';
this.snackbar.show = true;
}).catch(error => {
this.loading = false;
this.snackbar.text = 'خطا در ذخیره اطلاعات';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error saving inventory:', error);
});
}).catch(error => {
this.loading = false;
this.snackbar.text = this.$t('dialog.inventory.save_error');
this.snackbar.text = 'خطا در بررسی مجوز';
this.snackbar.color = 'error';
this.snackbar.show = true;
console.error('Error saving inventory:', error);
console.error('Error checking permission:', error);
});
},
validateInventory() {