Skip to content

Commit d53b2cd

Browse files
authored
Improve transaction page for non paygo appliances with associated device (#1279)
1 parent 4253d3d commit d53b2cd

File tree

7 files changed

+203
-5
lines changed

7 files changed

+203
-5
lines changed

src/backend/app/Services/TransactionService.php

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace App\Services;
44

5+
use App\Models\ApplianceRate;
56
use App\Models\Meter\Meter;
67
use App\Models\Transaction\Transaction;
78
use App\Services\Interfaces\IAssociative;
@@ -335,13 +336,37 @@ public function save($transaction): bool {
335336
}
336337

337338
public function getById(int $id): Transaction {
338-
return $this->transaction->newQuery()->with([
339+
$transaction = $this->transaction->newQuery()->with([
339340
'token',
340341
'originalTransaction',
341342
'originalTransaction.conflicts',
342343
'sms',
343344
'paymentHistories',
344-
'device' => fn ($q) => $q->whereHas('person')->with(['device', 'person'])])->find($id);
345+
'paymentHistories.paidFor',
346+
'device' => fn ($q) => $q->whereHas('person')->with(['device', 'person']),
347+
'appliance' => fn ($q) => $q->with(['appliance', 'person']),
348+
])->find($id);
349+
350+
// Load user relationship for cash transactions only
351+
if ($transaction && $transaction->original_transaction_type === 'cash_transaction') {
352+
$transaction->originalTransaction->load('user');
353+
}
354+
355+
// For non-PAYGO appliances (no device), try to find the appliance through payment histories
356+
if ($transaction && !$transaction->device && !$transaction->appliance && $transaction->paymentHistories->isNotEmpty()) {
357+
$applianceRate = $transaction->paymentHistories
358+
->filter(fn ($ph): bool => $ph->paid_for_type === ApplianceRate::class)
359+
->first()?->paidFor;
360+
361+
if ($applianceRate instanceof ApplianceRate) {
362+
$transaction->setRelation(
363+
'appliance',
364+
$applianceRate->appliancePerson()->with(['appliance', 'person'])->first()
365+
);
366+
}
367+
}
368+
369+
return $transaction;
345370
}
346371

347372
/**

src/frontend/src/assets/locales/ar.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
"bulkSms": "تم إرسال الرسائل بنجاح | هل أنت متأكد من إرسال الرسائل الجماعية؟ | رسائل قصيرة جماعية",
153153
"businessNumber": "رقم العمل",
154154
"callbackUrl": "رابط الاستدعاء",
155+
"cashTransaction": "معاملة نقدية",
155156
"changePassword": "تغيير كلمة السر",
156157
"clickPaymentLink": "انقر على رابط الدفع",
157158
"closedTicket": "تذكرة مغلقة",
@@ -176,6 +177,7 @@
176177
"createPaymentForCustomer": "إنشاء دفعة للعميل",
177178
"createPaymentLink": "إنشاء رابط الدفع",
178179
"createdAt": "أُنشئت في",
180+
"createdBy": "أنشأه",
179181
"createdDate": "تاريخ الإنشاء",
180182
"customerDeletedSuccess": "تم حذف العميل بنجاح",
181183
"customerList": "قائمة الحرفاء",
@@ -304,6 +306,7 @@
304306
"newVillageNotify": "تم تخزين القرية التي أضفتها بنجاح.",
305307
"noData": "لم يتم العثور على بيانات | لا توجد بيانات",
306308
"noDataFoundFor": " ‏{data} ‏ لم يتم العثور على بيانات لـ",
309+
"noDeviceAssigned": "لم يتم تعيين جهاز",
307310
"noOne": "لا أحد",
308311
"numberOfAgents": "عدد الوكلاء",
309312
"onlyApproved": "الموافق عليها فقط",
@@ -431,6 +434,7 @@
431434
"transactionNotify": "لا توجد بيانات كافية للمقارنة",
432435
"transactionProcessing": "جاري معالجة المعاملة",
433436
"transactionReference": "مرجع المعاملة",
437+
"transactionType": "نوع المعاملة",
434438
"unauthorizedDescription": "لا تملك صلاحية الوصول إلى هذا القسم. تواصل مع المسؤول إذا كنت تعتقد أن هذا خطأ.",
435439
"untraceableTransaction": "معاملة غير قابلة للتتبع",
436440
"updateAddress": "تحديث العنوان",

src/frontend/src/assets/locales/bu.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
"bulkSms": "အစုလိကု ်စာတို SMS |sms အများအြပားပUိရန် ေသချာပါသလား? | Sms(es)ေတွ ပUိ ေနတယ် ",
153153
"businessNumber": "လပု်ငနး်နပံါတ်",
154154
"callbackUrl": "ပြန်ခေါ် URL",
155+
"cashTransaction": "ငွေသားငွေလွှဲ",
155156
"changePassword": " စကားဝှက်ကိုေြပာင်းရန",
156157
"clickPaymentLink": "Click on the payment link",
157158
"closedTicket": " လက်မှတ်ပိတ်",
@@ -176,6 +177,7 @@
176177
"createPaymentForCustomer": "Create Payment for Customer",
177178
"createPaymentLink": "Create Payment Link",
178179
"createdAt": "တငွ ် ဖနတ် ီးခဲ့သည်။",
180+
"createdBy": "ဖန်တီးသူ",
179181
"createdDate": "ဖနတ် ီးသည့်ရက်စဲွ",
180182
"customerDeletedSuccess": "ဖောက်သည်ကိုအောင်မြင်စွာ ဖျက်ပြီးပါပြီ",
181183
"customerList": " ေဖာက်သည် စာရင်း",
@@ -304,6 +306,7 @@
304306
"newVillageNotify": "သင်ထည့်ထားေသာေကျးရွာကို ေအာင်ြမင်စွာ သိမ်းဆည်းထားသည်။",
305307
"noData": "ေဒတာမGှိပါ။|ေဒတာမေတပFါ",
306308
"noDataFoundFor": "{ေဒတာ}အတကွ်ေဒတာမေတပFါ",
309+
"noDeviceAssigned": "စက်ပစ္စည်းမသတ်မှတ်ထားပါ",
307310
"noOne": "ဘယ်သူမှ",
308311
"numberOfAgents": "ေအးဂျင်အရေအတွက်",
309312
"onlyApproved": "အတည်ြပ+ြခင်းသာြဖစ်သည်",
@@ -431,6 +434,7 @@
431434
"transactionNotify": "Jှ+ိင်းယှV်ရန်အချက်အလက်လံေုလာက်မ6မGှိပါ။",
432435
"transactionProcessing": "ေငေွပးေငယွ ူေဆာင်ရွက်ြခင်း",
433436
"transactionReference": "Transaction Reference",
437+
"transactionType": "ငွေလွှဲအမျိုးအစား",
434438
"unauthorizedDescription": "You don't have the required permission to view this section. Reach out to your administrator if you believe this is a mistake.",
435439
"untraceableTransaction": "Untraceable transaction",
436440
"updateAddress": "လိပ်စာ မွမ်းမံပါ",

src/frontend/src/assets/locales/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
"bulkSms": "Bulk SMS | Are you sure to send the bulk SMS? | The SMS(es) are send out",
153153
"businessNumber": "Business Number",
154154
"callbackUrl": "Callback URL",
155+
"cashTransaction": "Cash Transaction",
155156
"changePassword": "Change Password",
156157
"clickPaymentLink": "Click on the payment link",
157158
"closedTicket": "Closed Ticket",
@@ -176,6 +177,7 @@
176177
"createPaymentForCustomer": "Create Payment for Customer",
177178
"createPaymentLink": "Create Payment Link",
178179
"createdAt": "Created At",
180+
"createdBy": "Created By",
179181
"createdDate": "Created Date",
180182
"customerDeletedSuccess": "Customer Deleted Successfully",
181183
"customerList": "Customer List",
@@ -304,6 +306,7 @@
304306
"newVillageNotify": "The Village you add is stored successfully.",
305307
"noData": "No Data | No Data Found",
306308
"noDataFoundFor": "No Data Found For {data}",
309+
"noDeviceAssigned": "No Device Assigned",
307310
"noOne": "No One",
308311
"numberOfAgents": "Number of Agents",
309312
"onlyApproved": "Only Approved",
@@ -431,6 +434,7 @@
431434
"transactionNotify": "There is not enough data to compare",
432435
"transactionProcessing": "Transaction Processing",
433436
"transactionReference": "Transaction Reference",
437+
"transactionType": "Transaction Type",
434438
"unauthorizedDescription": "You don't have the required permission to view this section. Reach out to your administrator if you believe this is a mistake.",
435439
"untraceableTransaction": "Untraceable transaction",
436440
"updateAddress": "Update Address",

src/frontend/src/assets/locales/fr.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@
152152
"bulkSms": "SMS en vrac | Êtes-vous sûr(e) de vouloir envoyer les SMS en vrac ? | Les SMS sont envoyés.",
153153
"businessNumber": "Numéro de l'entreprise",
154154
"callbackUrl": "URL de rappel",
155+
"cashTransaction": "Transaction en espèces",
155156
"changePassword": "Changer le mot de passe",
156157
"clickPaymentLink": "Cliquez sur le lien de paiement",
157158
"closedTicket": "Ticket fermé",
@@ -176,6 +177,7 @@
176177
"createPaymentForCustomer": "Create Payment for Customer",
177178
"createPaymentLink": "Create Payment Link",
178179
"createdAt": "Created At",
180+
"createdBy": "Créé par",
179181
"createdDate": "Created Date",
180182
"customerDeletedSuccess": "Customer Deleted Successfully",
181183
"customerList": "Customer List",
@@ -304,6 +306,7 @@
304306
"newVillageNotify": "The Village you add is stored successfully.",
305307
"noData": "No Data | No Data Found",
306308
"noDataFoundFor": "No Data Found For {data}",
309+
"noDeviceAssigned": "Aucun appareil assigné",
307310
"noOne": "No One",
308311
"numberOfAgents": "Number of Agents",
309312
"onlyApproved": "Only Approved",
@@ -431,6 +434,7 @@
431434
"transactionNotify": "There is not enough data to compare",
432435
"transactionProcessing": "Transaction Processing",
433436
"transactionReference": "Transaction Reference",
437+
"transactionType": "Type de transaction",
434438
"unauthorizedDescription": "Vous n'avez pas les droits requis pour voir cette section. Contactez votre administrateur si vous pensez qu'il s'agit d'une erreur.",
435439
"untraceableTransaction": "Untraceable transaction",
436440
"updateAddress": "Update Address",
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
<template>
2+
<div>
3+
<div class="md-layout">
4+
<div class="md-layout-item md-subheader">
5+
{{ $tc("phrases.transactionType") }}
6+
</div>
7+
<div class="md-layout-item md-subheader n-font">
8+
{{ $tc("phrases.cashTransaction") }}
9+
</div>
10+
</div>
11+
<hr class="hr-d" />
12+
<div class="md-layout">
13+
<div class="md-layout-item md-subheader">
14+
{{ $tc("words.status") }}
15+
</div>
16+
<div class="md-layout-item md-subheader n-font">
17+
<span v-if="ot.status === 1" class="status-success">
18+
{{ $tc("words.confirm", 2) }}
19+
</span>
20+
<span v-else-if="ot.status === 0" class="status-pending">
21+
{{ $tc("words.process", 3) }}
22+
</span>
23+
<span v-else class="status-failed">
24+
{{ $tc("words.reject", 2) }}
25+
</span>
26+
</div>
27+
</div>
28+
<hr class="hr-d" />
29+
<div class="md-layout" v-if="ot.user">
30+
<div class="md-layout-item md-subheader">
31+
{{ $tc("phrases.createdBy") }}
32+
</div>
33+
<div class="md-layout-item md-subheader n-font">
34+
{{ ot.user.name }}
35+
</div>
36+
</div>
37+
</div>
38+
</template>
39+
40+
<script>
41+
export default {
42+
name: "CashTransactionDetail",
43+
props: {
44+
ot: {
45+
type: Object,
46+
required: true,
47+
},
48+
},
49+
}
50+
</script>
51+
52+
<style scoped>
53+
.n-font {
54+
font-weight: 100 !important;
55+
}
56+
57+
.hr-d {
58+
height: 1pt;
59+
margin: auto;
60+
padding: 0;
61+
display: block;
62+
border: 0;
63+
background-color: rgba(0, 0, 0, 0.12);
64+
}
65+
66+
.status-success {
67+
color: #4caf50;
68+
font-weight: 500;
69+
}
70+
71+
.status-pending {
72+
color: #ff9800;
73+
font-weight: 500;
74+
}
75+
76+
.status-failed {
77+
color: #f44336;
78+
font-weight: 500;
79+
}
80+
</style>

src/frontend/src/modules/Transactions/Transaction.vue

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,18 +82,23 @@
8282
{{ $tc("words.deviceType") }}
8383
</div>
8484
<div class="md-layout-item md-subheader n-font">
85-
{{ $tc(`words.${transaction.device.device_type}`) }}
85+
{{ deviceType }}
8686
</div>
8787
</div>
8888
<hr class="hr-d" />
8989
<div class="md-layout">
9090
<div class="md-layout-item md-subheader">
91-
{{ $tc("words.device") }}
91+
{{
92+
transaction.device
93+
? $tc("words.device")
94+
: $tc("words.appliance")
95+
}}
9296
</div>
9397
<div
9498
class="md-layout-item md-subheader n-font"
9599
v-if="
96100
transaction.payment_histories[0].paymentHistory &&
101+
transaction.device &&
97102
transaction.device.device_type === 'meter'
98103
"
99104
>
@@ -110,6 +115,7 @@
110115
class="md-layout-item md-subheader n-font"
111116
v-else-if="
112117
transaction.payment_histories[0].paymentHistory &&
118+
transaction.device &&
113119
transaction.device.device_type === 'solar_home_system'
114120
"
115121
>
@@ -124,8 +130,41 @@
124130
{{ transaction.message }}
125131
</router-link>
126132
</div>
133+
<div
134+
class="md-layout-item md-subheader n-font"
135+
v-else-if="
136+
transaction.appliance && transaction.appliance.id
137+
"
138+
>
139+
<router-link
140+
:to="{
141+
path:
142+
'/sold-appliance-detail/' +
143+
transaction.appliance.id,
144+
}"
145+
class="nav-link"
146+
>
147+
{{ deviceDisplay }}
148+
</router-link>
149+
</div>
150+
<div
151+
class="md-layout-item md-subheader n-font"
152+
v-else-if="
153+
isApplianceTransaction && applianceIdFromMessage
154+
"
155+
>
156+
<router-link
157+
:to="{
158+
path:
159+
'/sold-appliance-detail/' + applianceIdFromMessage,
160+
}"
161+
class="nav-link"
162+
>
163+
{{ deviceDisplay }}
164+
</router-link>
165+
</div>
127166
<div class="md-layout-item md-subheader n-font" v-else>
128-
{{ transaction.message }}
167+
{{ deviceDisplay }}
129168
</div>
130169
</div>
131170
<hr class="hr-d" />
@@ -308,6 +347,7 @@ import { timing } from "@/mixins/timing"
308347
import { currency } from "@/mixins/currency"
309348
import PaymentHistoryChart from "@/modules/Transactions/PaymentHistoryChart"
310349
import AgentTransactionDetail from "@/modules/Agent/AgentTransactionDetail"
350+
import CashTransactionDetail from "@/modules/Transactions/CashTransactionDetail"
311351
import Widget from "@/shared/Widget.vue"
312352
import { TransactionService } from "@/services/TransactionService"
313353
import { PersonService } from "@/services/PersonService"
@@ -320,6 +360,7 @@ export default {
320360
components: {
321361
Widget,
322362
AgentTransactionDetail,
363+
CashTransactionDetail,
323364
PaymentHistoryChart,
324365
},
325366
created() {
@@ -360,10 +401,46 @@ export default {
360401
return "WaveComTransactionDetail"
361402
case "paystack_transaction":
362403
return "PaystackTransactionDetail"
404+
case "cash_transaction":
405+
return "CashTransactionDetail"
363406
default:
364407
return null
365408
}
366409
},
410+
deviceType() {
411+
if (this.transaction.device && this.transaction.device.device_type) {
412+
return this.$tc(`words.${this.transaction.device.device_type}`)
413+
}
414+
if (this.transaction.appliance && this.transaction.appliance.appliance) {
415+
return this.transaction.appliance.appliance.name
416+
}
417+
return this.$tc("words.appliance")
418+
},
419+
deviceDisplay() {
420+
if (this.transaction.device) {
421+
return this.transaction.message
422+
}
423+
if (this.transaction.appliance && this.transaction.appliance.appliance) {
424+
return this.transaction.appliance.appliance.name
425+
}
426+
return this.transaction.message !== "-"
427+
? this.transaction.message
428+
: this.$tc("phrases.noDeviceAssigned")
429+
},
430+
isApplianceTransaction() {
431+
return (
432+
this.transaction.type === "deferred_payment" &&
433+
this.transaction.original_transaction_type === "cash_transaction" &&
434+
!this.transaction.device
435+
)
436+
},
437+
applianceIdFromMessage() {
438+
const message = this.transaction.message
439+
if (message && message !== "-" && /^\d+$/.test(message)) {
440+
return parseInt(message, 10)
441+
}
442+
return null
443+
},
367444
},
368445
methods: {
369446
async getDetail(id) {

0 commit comments

Comments
 (0)