bug fix in pay invoices

This commit is contained in:
Hesabix 2025-03-22 12:25:28 +00:00
parent 5a330c36a2
commit ae3d427740
14 changed files with 142 additions and 71 deletions

View file

@ -28,7 +28,7 @@ class PayController extends AbstractController
#[Route('/pay/sell/{id}', name: 'pay_sell')]
public function pay_sell(string $id, PayMGR $payMGR, twigFunctions $twigFunctions, EntityManagerInterface $entityManager, Log $log): Response
{
$doc = $entityManager->getRepository(HesabdariDoc::class)->find($id);
$doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy(['shortlink'=>$id]);
if (!$doc)
throw $this->createNotFoundException();
@ -49,7 +49,7 @@ class PayController extends AbstractController
$tempPay->setDoc($doc);
$entityManager->persist($tempPay);
$entityManager->flush();
$result = $payMGR->createRequest($amountPay, $this->generateUrl('pay_sell_verify', ["id" => $doc->getId()], UrlGeneratorInterface::ABSOLUTE_URL), 'پرداخت فاکتور شماره ' . $doc->getCode() . ' کسب و کار ' . $doc->getBid()->getLegalName());
$result = $payMGR->createRequest($amountPay, $this->generateUrl('pay_sell_verify', ["id" => $tempPay->getId()], UrlGeneratorInterface::ABSOLUTE_URL), 'پرداخت فاکتور شماره ' . $doc->getCode() . ' کسب و کار ' . $doc->getBid()->getLegalName());
if ($result['Success']) {
$tempPay->setGatePay($result['gate']);
$tempPay->setVerifyCode($result['authkey']);
@ -77,7 +77,7 @@ class PayController extends AbstractController
$res = $payMGR->verify($req->getPrice(), $req->getVerifyCode(), $request);
if ($res['Success'] == false) {
$log->insert('کیف پول', 'خطا در پرداخت فاکتور فروش ' . $doc->getCode(), $this->getUser(), $doc->getBid());
return $this->redirectToRoute('shortlinks_show', ['type' => 'sell', 'bid' => $doc->getBid()->getId(), 'link' => $doc->getId(), 'msg' => 'fail']);
return $this->redirectToRoute('shortlinks_show', ['type' => 'sell', 'bid' => $doc->getBid()->getId(), 'link' => $doc->getShortlink(), 'msg' => 'fail']);
} else {
$req->setStatus(100);
$req->setRefID($res['refID']);

View file

@ -59,12 +59,6 @@ class ShortlinksController extends AbstractController
'bid' => $bus
]);
if (!$doc) {
$doc = $entityManager->getRepository(HesabdariDoc::class)->findOneBy([
'type' => 'sell',
'id' => $link,
'bid' => $bus
]);
if (!$doc)
throw $this->createNotFoundException();
}

View file

@ -22,7 +22,12 @@ class UiGeneralController extends AbstractController
$name = $registryManager->get('system', 'appName');
return $this->json($name);
}
#[Route('/system/getslogon', name: 'general_get_slogon')]
public function general_get_slogon(registryMGR $registryManager): JsonResponse
{
$name = $registryManager->get('system', 'appSlogon');
return $this->json($name);
}
#[Route('/system/geturl', name: 'general_get_url')]
public function general_get_url(registryMGR $registryManager): JsonResponse
{

View file

@ -39,7 +39,7 @@
چاپ فاکتور
</a>
{% if (totalPays < doc.amount) and bid.walletEnable and doc.money.name == 'IRR' %}
<a href="{{ path('pay_sell',{'id':doc.id}) }}" class="btn btn-sm btn-success">
<a href="{{ path('pay_sell',{'id':doc.shortlink}) }}" class="btn btn-sm btn-success">
<i class="fa fa-credit-card"></i>
پرداخت آنلاین مبلغ
{{ (doc.amount - totalPays) | number_format }}

View file

@ -10,7 +10,7 @@
<title>حسابداری آنلاین</title>
<!-- Manifest -->
<link rel="manifest" href="/u/manifest.json" />
<link rel="manifest" href="/manifest.json" />
<!-- Icons -->
<!-- The following icons can be replaced with your own, they are used by desktop and mobile browsers -->
<link href="/img/favicons/favicon.png" rel="shortcut icon" />

View file

@ -6,7 +6,7 @@
"related_applications": [
{
"platform": "webapp",
"url": "/u/manifest.json"
"url": "/manifest.json"
}
],
"display": "standalone",

View file

@ -1,52 +1,91 @@
import axios from 'axios';
// ثابت‌ها
const KEYS = {
DEV_API_URL: 'dev_api_url',
DEV_ALERT_SHOWN: 'dev_mode_alert_shown',
SITE_NAME: 'hesabix_site_name',
SITE_SLOGON: 'hesabix_site_slogon'
};
const DEFAULTS = {
SITE_NAME: 'حسابیکس',
SITE_SLOGON: 'حسابیکس سامانه جامع مدیریت کسب‌و‌کار'
};
export const name = "hesabixConfig";
// کش برای API URL
let cachedApiUrl = null;
export function getApiUrl() {
const origin = window.location.origin; // دامنه اصلی مثل http://localhost.com
const path = window.location.pathname; // مسیر فعلی مثل /app/etc/u
if (cachedApiUrl) return cachedApiUrl;
// مسیر رو به آرایه تبدیل می‌کنم تا بتونم پوشه‌ها رو جدا کنم
const pathParts = path.split('/').filter(part => part !== ''); // ['app', 'etc', 'u']
const devApiUrl = localStorage.getItem(KEYS.DEV_API_URL);
const alertShown = localStorage.getItem(KEYS.DEV_ALERT_SHOWN);
// پیدا کردن جایگاه u و حذفش به همراه هر چی بعدش هست
if (devApiUrl) {
if (!alertShown) {
alert(`شما در حالت توسعه هستید و به آدرس زیر متصل می‌شوید:\n${devApiUrl}`);
localStorage.setItem(KEYS.DEV_ALERT_SHOWN, 'true');
}
cachedApiUrl = devApiUrl;
return devApiUrl;
}
const origin = window.location.origin;
const pathParts = window.location.pathname.split('/').filter(part => part !== '');
const uIndex = pathParts.indexOf('u');
if (uIndex !== -1) {
// فقط مسیر تا قبل از u رو نگه می‌دارم
const basePath = pathParts.slice(0, uIndex).join('/'); // app/etc
if (basePath === '') {
return `${origin}`;
}
return `${origin}/${basePath}`; // http://localhost.com/app/etc
const basePath = pathParts.slice(0, uIndex).join('/');
cachedApiUrl = basePath ? `${origin}/${basePath}` : origin;
} else {
cachedApiUrl = origin;
}
// اگه u توی مسیر نبود، مسیر روت رو برگشت بده
return `${origin}`;
return cachedApiUrl;
}
// تابع کمکی برای گرفتن داده از سرور و کش کردن
async function fetchAndCache(url, localStorageKey, defaultValue) {
const storedValue = localStorage.getItem(localStorageKey);
if (storedValue) return storedValue;
try {
const response = await axios.get(url);
if (response.status === 200) {
const data = response.data;
localStorage.setItem(localStorageKey, data);
return data;
}
throw new Error('پاسخ نامعتبر از سرور');
} catch (error) {
console.error(`خطا در گرفتن داده از ${url}:`, error);
return defaultValue;
}
}
export async function getSiteName() {
// کلید ذخیره‌سازی در localStorage
const localStorageKey = 'hesabix_site_name';
// چک کن که آیا نام برنامه توی localStorage هست یا نه
const storedName = localStorage.getItem(localStorageKey);
if (storedName) {
return storedName; // اگه بود، همون رو برگشت بده
return fetchAndCache(
`${getApiUrl()}/system/getname`,
KEYS.SITE_NAME,
DEFAULTS.SITE_NAME
);
}
try {
// اگه نبود، درخواست به سمفونی ارسال کن
const response = await axios.get(`${getApiUrl()}/system/getname`);
const siteName = response.data; // فرض می‌کنم سمفونی نام رو مستقیم برمی‌گردونه
// ذخیره توی localStorage
localStorage.setItem(localStorageKey, siteName);
return siteName;
} catch (error) {
console.error('خطا در گرفتن نام برنامه از سرور:', error);
// اگه خطایی بود، یه مقدار پیش‌فرض برگشت بده
return 'حسابیکس';
export async function getSiteSlogon() {
return fetchAndCache(
`${getApiUrl()}/system/getslogon`,
KEYS.SITE_SLOGON,
DEFAULTS.SITE_SLOGON
);
}
export function getBasePath() {
const fullPath = window.location.pathname;
const uIndex = fullPath.indexOf('/u');
return uIndex !== -1 ? fullPath.substring(0, uIndex + '/u'.length) + '/' : '/u/';
}
export function getVersionCheckerUrl() {

View file

@ -443,8 +443,8 @@ const fa_lang = {
name: "نام و نام خانوادگی",
name_des: "مثلا علی باقری",
password_register_des: "کلمه عبور باید بیشتر از ۱۰ کاراکتر و ترکیبی از اعداد و حروف باشد",
login_label: "ورود به حسابیکس",
register_label: "عضویت در حسابیکس",
login_label: "ورود",
register_label: "عضویت",
login: "ورود",
email_placeholder: "پست الکترونیکی خود را وارد کنید",
email: "پست الکترونیکی",
@ -476,7 +476,7 @@ const fa_lang = {
history: "تاریخچه",
send_code_forget_password: "ارسال کد بازیابی",
number_edited: "شماره تلفن با موفقیت تغییر یافت . کد فعال سازی جدید به شماره شما ارسال شد",
register_terms_des: "عضویت در حسابیکس به معنای قبول شرایط و مقررات استفاده از آن است.برای مشاهده متن توافقنامه به صفحه نخست مراجعه نمایید",
register_terms_des: "عضویت به معنای قبول شرایط و مقررات استفاده از آن است.برای مشاهده متن توافقنامه به صفحه نخست مراجعه نمایید",
"referral_link": "لینک دعوت از دیگران",
"link_copied": "لینک با موفقیت کپی شد!",
"referral_not_available": "لینک عضویت در دسترس نیست",
@ -498,7 +498,7 @@ const fa_lang = {
}
},
login: {
des: "برای ورود به حسابیکس شماره تلفن و کلمه عبور خود را وارد کنید.در صورتی که هنوز عضو نیستید با کلیک بر روی دکمه عضویت و برای بازیابی کلمه عبور از دکمه فراموشی کلمه عبور استفاده نمایید.",
des: "برای ورود شماره تلفن و کلمه عبور خود را وارد کنید.در صورتی که هنوز عضو نیستید با کلیک بر روی دکمه عضویت و برای بازیابی کلمه عبور از دکمه فراموشی کلمه عبور استفاده نمایید.",
input_fail: "شماره تلفن یا کلمه عبور اشتباه است"
},
validator: {

View file

@ -942,7 +942,7 @@ const router = createRouter({
name: 'install_pwa',
component: () => import('../views/user/InstallPWA.vue'),
meta: {
'title': 'نصب وب اپلیکیشن حسابیکس',
'title': 'نصب وب اپلیکیشن ',
}
},
{

View file

@ -2,7 +2,7 @@
import { RouterLink, RouterView } from 'vue-router';
import axios from "axios";
import Swal from "sweetalert2";
import { getApiUrl, getSiteName } from "@/hesabixConfig";
import { getApiUrl, getBasePath, getSiteName } from "@/hesabixConfig";
import { ref } from 'vue';
import Profile_btn from '@/components/application/buttons/profile_btn.vue';
import Notifications_btn from '@/components/application/buttons/notifications_btn.vue';
@ -18,6 +18,8 @@ export default {
business: { id: '', name: '' },
timeNow: '',
apiUrl: '',
siteName: '',
siteSlogon: '',
permissions: {},
showShortcutsDialog: false,
isEditingShortcuts: false,
@ -63,14 +65,18 @@ export default {
window.addEventListener('keydown', this.handleKeyDown);
window.addEventListener('keyup', this.handleKeyUp);
},
created() {
this.siteName = getSiteName();
async created() {
this.siteName = await getSiteName();
this.siteSlogon = await getSiteSlogon();
},
beforeUnmount() {
window.removeEventListener('keydown', this.handleKeyDown);
window.removeEventListener('keyup', this.handleKeyUp);
},
methods: {
getbase() {
return getBasePath();
},
deleteBusiness() {
Swal.fire({
text: 'آیا برای حذف این کسب‌و‌کار مطمئن هستید؟ بعد از تایید این عملیات کسب و کار شما به مدت یک ماه در پایگاه داده آرشیو و بعد از آن به صورت دائم حذف خواهد شد',
@ -282,7 +288,7 @@ export default {
<template>
<v-system-bar color="primaryLight2">
<v-avatar image="/img/logo-blue.png" size="20" class="me-2 d-none d-sm-flex" />
<span class="d-none d-sm-flex">{{ $t('hesabix.banner') }}</span>
<span class="d-none d-sm-flex">{{ siteSlogon }}</span>
<v-avatar :image="apiUrl + '/front/avatar/file/get/' + business.id" size="20" class="me-2 d-flex d-sm-none" />
<span class="d-flex d-sm-none">{{ business.name }}</span>
<v-spacer />
@ -290,10 +296,10 @@ export default {
</v-system-bar>
<v-navigation-drawer v-model="drawer" :width="300">
<v-card height="64" rounded="0" prepend-icon="mdi-account">
<template v-slot:title>{{ $t('app.name') }}</template>
<template v-slot:title>{{ siteName }}</template>
<template v-slot:prepend>
<v-avatar class="d-none d-sm-flex" :image="apiUrl + '/front/avatar/file/get/' + business.id" />
<v-avatar class="d-flex d-sm-none" image="./img/favw.png" />
<v-avatar class="d-flex d-sm-none" :image="getbase() + 'img/favw.png'" />
</template>
</v-card>
<v-list class="px-0 pt-0">
@ -961,6 +967,7 @@ export default {
.shortcut-input {
max-width: 60px;
}
.v-data-table {
overflow-x: auto;
}

View file

@ -5,7 +5,7 @@
<v-row class="d-flex flex-column align-center justify-center">
<img src="/img/logo-blue.png" width="120 " class="mt-2 mb-5 p-1" alt="" />
<h4 class="text-center mt-5 px-8">
نسخه وب اپلیکیشن (PWA) حسابیکس را به صفحه اصلی اضافه کنید.
نسخه وب اپلیکیشن (PWA) را به صفحه اصلی اضافه کنید.
</h4>
<p class="text-center mt-5 px-5">با این کار، میتوانید برای همیشه و بدون نیاز به بروزرسانی از خدمات اپلیکیشن استفاده کنید.</p>
<p class="text-center mt-5 px-5" v-if="chromeBanner">ابتدا از دکمه <span class="font-weight-bold text-indigo-darken-3">نصب</span> استفاده کنید و سپس <span class="font-weight-bold text-indigo-darken-3">Add</span> را بزنید. اگر برنامه نصب نشد مراحل بعدی را انجام دهید.</p>

View file

@ -10,7 +10,29 @@
<v-container class="pa-0 ma-0">
<v-card :loading="loading ? 'red' : null" :disabled="loading">
<v-card-text>
<v-row>
<!-- نمایش پیام در صورت خالی بودن لیست -->
<v-row v-if="!loading && contents.length === 0" justify="center" class="text-center pa-5">
<v-col cols="12">
<v-icon size="60" color="grey" class="mb-4">mdi-store-off-outline</v-icon>
<h3 class="text-h6 mb-3">
هنوز هیچ کسبوکاری ندارید!
</h3>
<p class="text-body-1 text-grey-darken-1">
برای شروع کار ، ابتدا یک کسبوکار ایجاد کنید یا از دیگران بخواهید شما را به کسبوکارشان دعوت کنند.
</p>
<v-btn
color="primary"
class="mt-4"
to="/profile/new-business"
prepend-icon="mdi-store-plus-outline"
>
ایجاد کسبوکار جدید
</v-btn>
</v-col>
</v-row>
<!-- نمایش لودینگ یا لیست کسبوکارها -->
<v-row v-else>
<v-col v-if="loading" cols="12" sm="12" md="12" class="pa-0 ma-0">
<v-skeleton-loader class="my-5 mx-5" :elevation="1" type="list-item-avatar"></v-skeleton-loader>
</v-col>

View file

@ -1,16 +1,16 @@
<template>
<v-system-bar color="primaryLight2">
<v-avatar image="/img/logo-blue.png" size="20" class="me-2" />
<span>{{ $t('hesabix.banner') }}</span>
<v-avatar :image="getbase() + 'img/logo-blue.png'" size="20" class="me-2" />
<span>{{ siteSlogon }}</span>
<v-spacer />
</v-system-bar>
<v-navigation-drawer v-model="drawer">
<v-card height="64" rounded="0" prepend-icon="mdi-account">
<template v-slot:title>
{{ $t('app.name') }}
{{ siteName }}
</template>
<template v-slot:prepend>
<v-avatar image="./img/favw.png" />
<v-avatar :image="getbase() + 'img/favw.png'" />
</template>
</v-card>
<v-list class="px-0 pt-0">
@ -45,7 +45,7 @@
<v-app-bar scroll-behavior="inverted elevate" scroll-threshold="0">
<v-app-bar-nav-icon @click="drawer = !drawer"></v-app-bar-nav-icon>
<v-app-bar-title>
{{ $t('app.name') }}
{{ siteName }}
</v-app-bar-title>
<v-spacer></v-spacer>
<v-tooltip :text="$t('dialog.exit')" location="bottom">
@ -63,7 +63,7 @@
<script lang="ts">
import axios from "axios";
import { getSiteName, getApiUrl } from "@/hesabixConfig"
import { getSiteName, getApiUrl, getBasePath, getSiteSlogon } from "@/hesabixConfig"
import { applicationStore } from "@/stores/applicationStore";
import { useUserStore } from "@/stores/userStore";
import { ref, defineComponent } from "vue";
@ -82,6 +82,7 @@ export default defineComponent({
},
siteName: '',
siteUrl: '',
siteSlogon:'',
ROLE_ADMIN: false,
user: {
mobile: '1'
@ -122,13 +123,16 @@ export default defineComponent({
...mapState(useUserStore, ['userData', 'synced']),
},
components: { Change_lang },
created() {
this.siteName = getSiteName();
async created() {
this.siteName = await getSiteName();
this.siteSlogon = await getSiteSlogon();
this.siteUrl = getApiUrl();
},
methods: {
...mapActions(useUserStore, ['refresh']),
getbase(){
return getBasePath();
},
logout() {
axios.post('/api/user/logout')
.then((response) => {

View file

@ -9,7 +9,7 @@
</v-toolbar>
<v-container class="pa-0 ma-0">
<v-card :loading="loading ? 'red' : null" :disabled="loading">
<v-card :disabled="loading">
<v-tabs v-model="activeTab" color="primary" grow>
<v-tab value="pending" class="flex-grow-1">
<v-icon start>mdi-progress-clock</v-icon> در حال پیگیری ({{ pendingItems.length }})