Skip to content

Commit 169cb21

Browse files
authored
Merge pull request #223 from harvardinformatics/dda_more_billing_record_summaries
Add Billing Summaries to Billing Record Summary page
2 parents 4388dc8 + 3fe1c84 commit 169cb21

12 files changed

+426
-61
lines changed

src/api/IFXAPI.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ import BillingRecord, { BillingTransaction } from '@/components/billingRecord/IF
1818
import { Product, ProductRate, Processing } from '@/components/product/IFXProduct'
1919
import ProductUsage from '@/components/productUsage/IFXProductUsage'
2020
import { ReportRun, Report } from '@/components/report/IFXReport'
21+
import AccountBillingSummary from '@/components/billingSummary/IFXAccountBillingSummary'
22+
import UserBillingSummary from '@/components/billingSummary/IFXUserBillingSummary'
23+
import ProductRateBillingSummary from '@/components/billingSummary/IFXProductRateBillingSummary'
2124

2225
function isNumeric(val) {
2326
return !Number.isNaN(parseFloat(val)) && Number.isFinite(val)
@@ -1020,6 +1023,41 @@ export default class IFXAPIService {
10201023
return this.axios.post(url, data, { headers: { 'Content-Type': 'application/json' } })
10211024
}
10221025

1026+
get accountBillingSummary() {
1027+
const baseURL = this.urls.GET_SUMMARY_BY_ACCOUNT
1028+
const createFunc = (accountBillingSummaryData, decompose = false) => {
1029+
const newAccountBillingSummaryData = cloneDeep(accountBillingSummaryData) || {}
1030+
// If decomposing, do not create a new object
1031+
return decompose ? newAccountBillingSummaryData : new AccountBillingSummary(newAccountBillingSummaryData)
1032+
}
1033+
const decomposeFunc = (newAccountBillingSummaryData) => createFunc(newAccountBillingSummaryData, true)
1034+
return this.genericAPI(baseURL, AccountBillingSummary, createFunc, decomposeFunc)
1035+
}
1036+
1037+
get userBillingSummary() {
1038+
const baseURL = this.urls.GET_SUMMARY_BY_USER
1039+
const createFunc = (userBillingSummaryData, decompose = false) => {
1040+
const newUserBillingSummaryData = cloneDeep(userBillingSummaryData) || {}
1041+
// If decomposing, do not create a new object
1042+
return decompose ? newUserBillingSummaryData : new UserBillingSummary(newUserBillingSummaryData)
1043+
}
1044+
const decomposeFunc = (newUserBillingSummaryData) => createFunc(newUserBillingSummaryData, true)
1045+
return this.genericAPI(baseURL, UserBillingSummary, createFunc, decomposeFunc)
1046+
}
1047+
1048+
get productRateBillingSummary() {
1049+
const baseURL = this.urls.GET_SUMMARY_BY_PRODUCT_RATE
1050+
const createFunc = (productRateBillingSummaryData, decompose = false) => {
1051+
const newProductRateBillingSummaryData = cloneDeep(productRateBillingSummaryData) || {}
1052+
// If decomposing, do not create a new object
1053+
return decompose
1054+
? newProductRateBillingSummaryData
1055+
: new ProductRateBillingSummary(newProductRateBillingSummaryData)
1056+
}
1057+
const decomposeFunc = (newProductRateBillingSummaryData) => createFunc(newProductRateBillingSummaryData, true)
1058+
return this.genericAPI(baseURL, ProductRateBillingSummary, createFunc, decomposeFunc)
1059+
}
1060+
10231061
getLabChargeHistory(facility, startMonth, startYear, endMonth, endYear) {
10241062
const params = {
10251063
start_month: startMonth,

src/components/billingRecord/IFXBillingRecordHeaderDecimal.vue

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,20 +38,13 @@ export default {
3838
type: Number,
3939
required: true,
4040
},
41-
getSummaryDetails: {
42-
type: Function,
43-
required: true,
44-
},
4541
},
4642
mounted() {
4743
this.localRowSelectionToggle = this.rowSelectionToggle.concat()
4844
},
4945
data() {
5046
return {
5147
localRowSelectionToggle: [],
52-
showSummaryDetail: false,
53-
summaryButtonText: 'Show',
54-
summaryDetails: [],
5548
}
5649
},
5750
computed: {},
@@ -61,13 +54,6 @@ export default {
6154
this.$emit('update:row-selection-toggle-indeterminate', this.rowSelectionToggleIndeterminateGroup)
6255
this.toggleGroup(this.group)
6356
},
64-
toggleSummaryDetail() {
65-
this.summaryButtonText = this.showSummaryDetail ? 'Show' : 'Hide'
66-
if (!this.showSummaryDetail && this.summaryDetails.length === 0) {
67-
this.summaryDetails = Array.from(this.getSummaryDetails(this.group).entries())
68-
}
69-
this.showSummaryDetail = !this.showSummaryDetail
70-
},
7157
},
7258
watch: {},
7359
}
@@ -93,17 +79,8 @@ export default {
9379
{{ $api.organization.parseSlug(group).name }}
9480
</span>
9581
<span class="ml-3 font-weight-medium">Total charges: {{ summaryCharges | dollars }}</span>
96-
<v-btn small text @click="toggleSummaryDetail" class="ml-2">{{ summaryButtonText }} Acct Summary</v-btn>
9782
</div>
9883
</v-row>
99-
<v-row v-if="showSummaryDetail">
100-
<v-col class="py-1 ml-9">
101-
<v-row v-for="entry in summaryDetails" :key="`${group}-${entry[0]}`" class="text-body-2">
102-
<v-col cols="5" class="ml-3">{{ entry[0] }}</v-col>
103-
<v-col class="text-xs-left ml-3 font-weight-medium">{{ entry[1] | dollars }}</v-col>
104-
</v-row>
105-
</v-col>
106-
</v-row>
10784
</td>
10885
</template>
10986
<style scoped lang="scss">

src/components/billingRecord/IFXBillingRecordListDecimal.vue

Lines changed: 7 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,13 @@ export default {
129129
{ text: 'Lab', value: 'account.organization', sortable: true },
130130
{ text: 'Expense Code / PO', value: 'account.slug', sortable: true },
131131
{ text: 'Product', value: 'product', sortable: true },
132-
{ text: 'Start Date', value: 'startDate', sortable: true, hide: !this.showDates && !this.showStartDate, namedSlot: true },
132+
{
133+
text: 'Start Date',
134+
value: 'startDate',
135+
sortable: true,
136+
hide: !this.showDates && !this.showStartDate,
137+
namedSlot: true,
138+
},
133139
{ text: 'End Date', value: 'endDate', sortable: true, hide: !this.showDates, namedSlot: true },
134140
{ text: 'Charge', value: 'decimalCharge', sortable: true, width: '100px' },
135141
{ text: 'Percent', value: 'percent', sortable: true, width: '100px' },
@@ -483,20 +489,6 @@ export default {
483489
const summary = records.reduce((prev, current) => prev + current.decimalCharge, 0)
484490
return summary
485491
},
486-
getSummaryDetails(group) {
487-
const records = this.filteredItems.filter((item) => item.account.organization === group)
488-
const expenseMap = new Map()
489-
records.forEach((item) => {
490-
const charge = item.decimalCharge
491-
if (expenseMap.has(item.account.slug)) {
492-
const value = expenseMap.get(item.account.slug)
493-
expenseMap.set(item.account.slug, value + charge)
494-
} else {
495-
expenseMap.set(item.account.slug, charge)
496-
}
497-
})
498-
return expenseMap
499-
},
500492
totalCharges() {
501493
const total = this.filteredItems.reduce((prev, current) => prev + current.decimalCharge, 0)
502494
return total
@@ -1127,7 +1119,6 @@ export default {
11271119
:rowSelectionToggleIndeterminateGroup.sync="rowSelectionToggleIndeterminate[group]"
11281120
:summaryCharges="summaryCharges(group)"
11291121
:toggleGroup="toggleGroup"
1130-
:getSummaryDetails="getSummaryDetails"
11311122
@
11321123
/>
11331124
</template>

src/components/billingRecord/IFXBillingRecords.vue

Lines changed: 101 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import moment from 'moment'
33
import { mapActions } from 'vuex'
44
import IFXBillingRecordListDecimal from '@/components/billingRecord/IFXBillingRecordListDecimal'
5+
import IFXGenericBillingSummaryList from '@/components/billingSummary/IFXGenericBillingSummaryList'
56
67
export default {
78
name: 'IFXBillingRecords',
@@ -63,6 +64,7 @@ export default {
6364
itemKey: 'key',
6465
showBillingRecords: false,
6566
keyModifier: 1,
67+
currentTabs: [],
6668
actions: [
6769
{
6870
key: 'approve',
@@ -77,6 +79,7 @@ export default {
7779
},
7880
components: {
7981
IFXBillingRecordListDecimal,
82+
IFXGenericBillingSummaryList,
8083
},
8184
methods: {
8285
...mapActions(['showMessage']),
@@ -97,12 +100,21 @@ export default {
97100
},
98101
async getFacilities() {
99102
this.facilities = await this.$api.facility.getList({ application_username: this.$api.vars.appName })
103+
this.facilities.forEach(() => {
104+
this.currentTabs.push(0)
105+
})
100106
},
101107
resetShowBillingRecords() {
102108
this.showBillingRecords = false
103109
this.keyModifier += 100
104110
this.showBillingRecords = true
105111
},
112+
getMonth() {
113+
return Number(this.date.split('-')[1])
114+
},
115+
getYear() {
116+
return Number(this.date.split('-')[0])
117+
},
106118
},
107119
watch: {
108120
date(val) {
@@ -157,23 +169,96 @@ export default {
157169
</v-container>
158170
</v-card-title>
159171
<v-container v-if="showBillingRecords">
160-
<v-row v-for="facility in facilities" :key="facility.id + keyModifier">
172+
<v-row v-for="(facility, i) in facilities" :key="facility.id + keyModifier">
161173
<v-col>
162-
<IFXBillingRecordListDecimal
163-
:facility="facility"
164-
:date="date"
165-
:organization="organization"
166-
:allowInvoiceGeneration="false"
167-
:allowApprovals="false"
168-
:allowDownloads="allowDownloads"
169-
:useDefaultMailButton="useDefaultMailButton"
170-
:allowChangeExpenseCode="allowChangeExpenseCode"
171-
:allowDeleteBillingRecords="allowDeleteBillingRecords"
172-
:showDates="showDates"
173-
:showStartDate="showStartDate"
174-
:showTotals="showTotals"
175-
:totalUnits="totalUnits"
176-
/>
174+
<v-tabs v-model="currentTabs[i]">
175+
<v-tab>Billing Records</v-tab>
176+
<v-tab>Summary by Account</v-tab>
177+
<v-tab>Summary by User</v-tab>
178+
<v-tab>Summary by Product Rate</v-tab>
179+
<v-tabs-items v-model="currentTabs[i]">
180+
<v-tab-item>
181+
<IFXBillingRecordListDecimal
182+
:facility="facility"
183+
:date="date"
184+
:organization="organization"
185+
:allowInvoiceGeneration="false"
186+
:allowApprovals="false"
187+
:allowDownloads="allowDownloads"
188+
:useDefaultMailButton="useDefaultMailButton"
189+
:allowChangeExpenseCode="allowChangeExpenseCode"
190+
:allowDeleteBillingRecords="allowDeleteBillingRecords"
191+
:showDates="showDates"
192+
:showStartDate="showStartDate"
193+
:showTotals="showTotals"
194+
:totalUnits="totalUnits"
195+
/>
196+
</v-tab-item>
197+
<v-tab-item>
198+
<IFXGenericBillingSummaryList
199+
:facility="facility"
200+
:month="getMonth()"
201+
:year="getYear()"
202+
itemType="genericBillingSummary"
203+
apiString="accountBillingSummary"
204+
:headers="[
205+
{ text: 'Account Name', value: 'name', sortable: true },
206+
{ text: 'Expense Code / PO', value: 'code', sortable: true },
207+
{
208+
text: 'Charges',
209+
value: 'totalDecimalCharge',
210+
sortable: true,
211+
namedSlot: true,
212+
width: '20rem',
213+
align: 'end',
214+
},
215+
]"
216+
/>
217+
</v-tab-item>
218+
<v-tab-item>
219+
<IFXGenericBillingSummaryList
220+
:facility="facility"
221+
:month="getMonth()"
222+
:year="getYear()"
223+
itemType="genericBillingSummary"
224+
apiString="userBillingSummary"
225+
:headers="[
226+
{ text: 'User', value: 'productUserFullName', sortable: true },
227+
{
228+
text: 'Charges',
229+
value: 'totalDecimalCharge',
230+
sortable: true,
231+
namedSlot: true,
232+
width: '20rem',
233+
align: 'end',
234+
},
235+
]"
236+
/>
237+
</v-tab-item>
238+
<v-tab-item>
239+
<IFXGenericBillingSummaryList
240+
:facility="facility"
241+
:month="getMonth()"
242+
:year="getYear()"
243+
itemType="genericBillingSummary"
244+
apiString="productRateBillingSummary"
245+
:extraParams="{ facility: facility.name }"
246+
:headers="[
247+
{ text: 'Product', value: 'productName', sortable: true },
248+
{ text: 'Rate', value: 'rateName', sortable: true },
249+
{
250+
text: 'Charges',
251+
value: 'totalDecimalCharge',
252+
sortable: true,
253+
namedSlot: true,
254+
width: '20rem',
255+
align: 'end',
256+
},
257+
]"
258+
/>
259+
</v-tab-item>
260+
</v-tabs-items>
261+
</v-tabs>
177262
</v-col>
178263
</v-row>
179264
</v-container>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import IFXItemBase from '@/components/item/IFXItemBase'
2+
3+
export default class AccountBillingSummary extends IFXItemBase {
4+
constructor(data = {}) {
5+
super(data)
6+
this.data = data
7+
}
8+
9+
get name() {
10+
return this.data.name
11+
}
12+
13+
set name(name) {
14+
this.data.name = name
15+
}
16+
17+
get code() {
18+
return this.data.code
19+
}
20+
21+
set code(code) {
22+
this.data.code = code
23+
}
24+
25+
get organization() {
26+
return this.data.organization
27+
}
28+
29+
set organization(organization) {
30+
this.data.organization = organization
31+
}
32+
33+
get accountType() {
34+
return this.data.account_type
35+
}
36+
37+
set accountType(accountType) {
38+
this.data.account_type = accountType
39+
}
40+
41+
get totalDecimalCharge() {
42+
return this.data.total_decimal_charge
43+
}
44+
45+
set totalDecimalCharge(totalDecimalCharge) {
46+
this.data.total_decimal_charge = totalDecimalCharge
47+
}
48+
49+
get month() {
50+
return this.data.month
51+
}
52+
53+
set month(month) {
54+
this.data.month = month
55+
}
56+
57+
get year() {
58+
return this.data.year
59+
}
60+
61+
set year(year) {
62+
this.data.year = year
63+
}
64+
}

0 commit comments

Comments
 (0)