Merge pull request #25869 from nextchamp-saqib/plaid-link-reset
fix(plaid): cannot reset plaid link for a bank account
diff --git a/.github/workflows/server-tests.yml b/.github/workflows/server-tests.yml
index de5cc61..92685e2 100644
--- a/.github/workflows/server-tests.yml
+++ b/.github/workflows/server-tests.yml
@@ -77,3 +77,34 @@
TYPE: server
CI_BUILD_ID: ${{ github.run_id }}
ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
+
+ - name: Upload Coverage Data
+ run: |
+ cp ~/frappe-bench/sites/.coverage ${GITHUB_WORKSPACE}
+ cd ${GITHUB_WORKSPACE}
+ pip3 install coverage==5.5
+ pip3 install coveralls==3.0.1
+ coveralls
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ COVERALLS_FLAG_NAME: run-${{ matrix.container }}
+ COVERALLS_SERVICE_NAME: ${{ github.event_name == 'pull_request' && 'github' || 'github-actions' }}
+ COVERALLS_PARALLEL: true
+
+ coveralls:
+ name: Coverage Wrap Up
+ needs: test
+ container: python:3-slim
+ runs-on: ubuntu-18.04
+ steps:
+ - name: Clone
+ uses: actions/checkout@v2
+
+ - name: Coveralls Finished
+ run: |
+ cd ${GITHUB_WORKSPACE}
+ pip3 install coverage==5.5
+ pip3 install coveralls==3.0.1
+ coveralls --finish
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/erpnext/accounts/doctype/journal_entry/regional/india.js b/erpnext/accounts/doctype/journal_entry/regional/india.js
new file mode 100644
index 0000000..75a69ac
--- /dev/null
+++ b/erpnext/accounts/doctype/journal_entry/regional/india.js
@@ -0,0 +1,17 @@
+frappe.ui.form.on("Journal Entry", {
+ refresh: function(frm) {
+ frm.set_query('company_address', function(doc) {
+ if(!doc.company) {
+ frappe.throw(__('Please set Company'));
+ }
+
+ return {
+ query: 'frappe.contacts.doctype.address.address.address_query',
+ filters: {
+ link_doctype: 'Company',
+ link_name: doc.company
+ }
+ };
+ });
+ }
+});
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/work_order/work_order.js b/erpnext/manufacturing/doctype/work_order/work_order.js
index a6086fb..3e5a72d 100644
--- a/erpnext/manufacturing/doctype/work_order/work_order.js
+++ b/erpnext/manufacturing/doctype/work_order/work_order.js
@@ -76,9 +76,9 @@
frm.set_query("production_item", function() {
return {
query: "erpnext.controllers.queries.item_query",
- filters:[
- ['is_stock_item', '=',1]
- ]
+ filters: {
+ "is_stock_item": 1,
+ }
};
});
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 1e8ce3c..3a7aa1b 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -781,3 +781,4 @@
erpnext.patches.v13_0.set_pos_closing_as_failed
erpnext.patches.v13_0.update_timesheet_changes
erpnext.patches.v13_0.set_training_event_attendance
+erpnext.patches.v13_0.rename_issue_status_hold_to_on_hold
diff --git a/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
new file mode 100644
index 0000000..48325fc
--- /dev/null
+++ b/erpnext/patches/v13_0/rename_issue_status_hold_to_on_hold.py
@@ -0,0 +1,20 @@
+# Copyright (c) 2020, Frappe and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import frappe
+
+def execute():
+ if frappe.db.exists('DocType', 'Issue'):
+ frappe.reload_doc("support", "doctype", "issue")
+ rename_status()
+
+def rename_status():
+ frappe.db.sql("""
+ UPDATE
+ `tabIssue`
+ SET
+ status = 'On Hold'
+ WHERE
+ status = 'Hold'
+ """)
\ No newline at end of file
diff --git a/erpnext/public/scss/shopping_cart.scss b/erpnext/public/scss/shopping_cart.scss
index 159a8a4..9402cf9 100644
--- a/erpnext/public/scss/shopping_cart.scss
+++ b/erpnext/public/scss/shopping_cart.scss
@@ -1,4 +1,3 @@
-@import "frappe/public/scss/desk/variables";
@import "frappe/public/scss/common/mixins";
body.product-page {
@@ -74,15 +73,6 @@
}
}
- // .card-body {
- // text-align: center;
- // }
-
- // .featured-item {
- // .card-body {
- // text-align: left;
- // }
- // }
.card-img-container {
height: 210px;
width: 100%;
@@ -217,12 +207,12 @@
border-color: var(--table-border-color) !important;
padding: 15px;
- @include media-breakpoint-between(xs, md) {
+ @media (max-width: var(--md-width)) {
height: 300px;
width: 300px;
}
- @include media-breakpoint-up(lg) {
+ @media (min-width: var(--lg-width)) {
height: 350px;
width: 350px;
}
@@ -233,11 +223,12 @@
}
.item-slideshow {
- @include media-breakpoint-between(xs, md) {
+
+ @media (max-width: var(--md-width)) {
max-height: 320px;
}
- @include media-breakpoint-up(lg) {
+ @media (min-width: var(--lg-width)) {
max-height: 430px;
}
@@ -254,7 +245,7 @@
cursor: pointer;
&:hover, &.active {
- border-color: $primary;
+ border-color: var(--primary);
}
}
@@ -316,12 +307,9 @@
}
.item-group-slideshow {
- .item-group-description {
- // max-width: 900px;
- }
.carousel-inner.rounded-carousel {
- border-radius: $card-border-radius;
+ border-radius: var(--card-border-radius);
}
}
diff --git a/erpnext/public/scss/website.scss b/erpnext/public/scss/website.scss
index 56b717c..f4325c0 100644
--- a/erpnext/public/scss/website.scss
+++ b/erpnext/public/scss/website.scss
@@ -1,4 +1,3 @@
-@import "frappe/public/scss/website/variables";
.filter-options {
max-height: 300px;
@@ -14,7 +13,7 @@
}
&.active {
- border-color: $primary;
+ border-color: var(--primary);
.check {
display: inline-flex;
@@ -25,7 +24,7 @@
.check {
display: inline-flex;
padding: 0.25rem;
- background: $primary;
+ background: var(--primary);
color: white;
border-radius: 50%;
font-size: 12px;
@@ -38,12 +37,12 @@
}
.result {
- border-bottom: 1px solid $border-color;
+ border-bottom: 1px solid var(--border-color);
}
.transaction-list-item {
padding: 1rem 0;
- border-top: 1px solid $border-color;
+ border-top: 1px solid var(--border-color);
position: relative;
a.transaction-item-link {
diff --git a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
index 3ddcc58..6415204 100644
--- a/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
+++ b/erpnext/regional/doctype/gstr_3b_report/gstr_3b_report.py
@@ -310,7 +310,7 @@
self.report_dict['sup_details']['osup_det']['txval'] += taxable_value
gst_category = self.invoice_detail_map.get(inv, {}).get('gst_category')
- place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply', '00-Other Territory')
+ place_of_supply = self.invoice_detail_map.get(inv, {}).get('place_of_supply') or '00-Other Territory'
if gst_category in ['Unregistered', 'Registered Composition', 'UIN Holders'] and \
self.gst_details.get("gst_state") != place_of_supply.split("-")[1]:
diff --git a/erpnext/selling/page/point_of_sale/pos_controller.js b/erpnext/selling/page/point_of_sale/pos_controller.js
index 4f4f1b2..ae3f9e3 100644
--- a/erpnext/selling/page/point_of_sale/pos_controller.js
+++ b/erpnext/selling/page/point_of_sale/pos_controller.js
@@ -241,10 +241,8 @@
events: {
get_frm: () => this.frm,
- cart_item_clicked: (item_code, batch_no, uom) => {
- const search_field = batch_no ? 'batch_no' : 'item_code';
- const search_value = batch_no || item_code;
- const item_row = this.frm.doc.items.find(i => i[search_field] === search_value && i.uom === uom);
+ cart_item_clicked: (item_code, batch_no, uom, rate) => {
+ const item_row = this.get_item_from_frm(item_code, batch_no, uom, rate);
this.item_details.toggle_item_details_section(item_row);
},
@@ -275,18 +273,25 @@
this.cart.toggle_numpad(minimize);
},
- form_updated: async (cdt, cdn, fieldname, value) => {
+ form_updated: (cdt, cdn, fieldname, value) => {
const item_row = frappe.model.get_doc(cdt, cdn);
if (item_row && item_row[fieldname] != value) {
- const { item_code, batch_no, uom } = this.item_details.current_item;
+ const { item_code, batch_no, uom, rate } = this.item_details.current_item;
const event = {
field: fieldname,
value,
- item: { item_code, batch_no, uom }
+ item: { item_code, batch_no, uom, rate }
}
return this.on_cart_update(event)
}
+
+ return Promise.resolve();
+ },
+
+ highlight_cart_item: (item) => {
+ const cart_item = this.cart.get_cart_item(item);
+ this.cart.toggle_item_highlight(cart_item);
},
item_field_focused: (fieldname) => {
@@ -501,8 +506,8 @@
let item_row = undefined;
try {
let { field, value, item } = args;
- const { item_code, batch_no, serial_no, uom } = item;
- item_row = this.get_item_from_frm(item_code, batch_no, uom);
+ const { item_code, batch_no, serial_no, uom, rate } = item;
+ item_row = this.get_item_from_frm(item_code, batch_no, uom, rate);
const item_selected_from_selector = field === 'qty' && value === "+1"
@@ -535,7 +540,7 @@
item_selected_from_selector && (value = flt(value))
- const args = { item_code, batch_no, [field]: value };
+ const args = { item_code, batch_no, rate, [field]: value };
if (serial_no) {
await this.check_serial_no_availablilty(item_code, this.frm.doc.set_warehouse, serial_no);
@@ -550,9 +555,11 @@
await this.check_stock_availability(item_row, value, this.frm.doc.set_warehouse);
await this.trigger_new_item_events(item_row);
-
- this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row);
+
this.update_cart_html(item_row);
+
+ this.item_details.$component.is(':visible') && this.edit_item_details_of(item_row);
+ this.check_serial_batch_selection_needed(item_row) && this.edit_item_details_of(item_row);
}
} catch (error) {
@@ -563,12 +570,13 @@
}
}
- get_item_from_frm(item_code, batch_no, uom) {
+ get_item_from_frm(item_code, batch_no, uom, rate) {
const has_batch_no = batch_no;
return this.frm.doc.items.find(
i => i.item_code === item_code
&& (!has_batch_no || (has_batch_no && i.batch_no === batch_no))
&& (i.uom === uom)
+ && (i.rate == rate)
);
}
diff --git a/erpnext/selling/page/point_of_sale/pos_item_cart.js b/erpnext/selling/page/point_of_sale/pos_item_cart.js
index 11a63b3..f5019f5 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_cart.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_cart.js
@@ -184,7 +184,8 @@
const item_code = unescape($cart_item.attr('data-item-code'));
const batch_no = unescape($cart_item.attr('data-batch-no'));
const uom = unescape($cart_item.attr('data-uom'));
- me.events.cart_item_clicked(item_code, batch_no, uom);
+ const rate = unescape($cart_item.attr('data-rate'));
+ me.events.cart_item_clicked(item_code, batch_no, uom, rate);
this.numpad_value = '';
});
@@ -520,28 +521,34 @@
}
}
- get_cart_item({ item_code, batch_no, uom }) {
+ get_cart_item({ item_code, batch_no, uom, rate }) {
const batch_attr = `[data-batch-no="${escape(batch_no)}"]`;
const item_code_attr = `[data-item-code="${escape(item_code)}"]`;
const uom_attr = `[data-uom="${escape(uom)}"]`;
+ const rate_attr = `[data-rate="${escape(rate)}"]`;
const item_selector = batch_no ?
- `.cart-item-wrapper${batch_attr}${uom_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}`;
+ `.cart-item-wrapper${batch_attr}${uom_attr}${rate_attr}` : `.cart-item-wrapper${item_code_attr}${uom_attr}${rate_attr}`;
return this.$cart_items_wrapper.find(item_selector);
}
+ get_item_from_frm(item) {
+ const doc = this.events.get_frm().doc;
+ const { item_code, batch_no, uom, rate } = item;
+ const search_field = batch_no ? 'batch_no' : 'item_code';
+ const search_value = batch_no || item_code;
+
+ return doc.items.find(i => i[search_field] === search_value && i.uom === uom && i.rate === rate);
+ }
+
update_item_html(item, remove_item) {
const $item = this.get_cart_item(item);
if (remove_item) {
$item && $item.next().remove() && $item.remove();
} else {
- const { item_code, batch_no, uom } = item;
- const search_field = batch_no ? 'batch_no' : 'item_code';
- const search_value = batch_no || item_code;
- const item_row = this.events.get_frm().doc.items.find(i => i[search_field] === search_value && i.uom === uom);
-
+ const item_row = this.get_item_from_frm(item);
this.render_cart_item(item_row, $item);
}
@@ -559,7 +566,7 @@
this.$cart_items_wrapper.append(
`<div class="cart-item-wrapper"
data-item-code="${escape(item_data.item_code)}" data-uom="${escape(item_data.uom)}"
- data-batch-no="${escape(item_data.batch_no || '')}">
+ data-batch-no="${escape(item_data.batch_no || '')}" data-rate="${escape(item_data.rate)}">
</div>
<div class="seperator"></div>`
)
@@ -636,13 +643,23 @@
function get_item_image_html() {
const { image, item_name } = item_data;
if (image) {
- return `<div class="item-image"><img src="${image}" alt="${image}""></div>`;
+ return `
+ <div class="item-image">
+ <img
+ onerror="cur_pos.cart.handle_broken_image(this)"
+ src="${image}" alt="${frappe.get_abbr(item_name)}"">
+ </div>`;
} else {
return `<div class="item-image item-abbr">${frappe.get_abbr(item_name)}</div>`;
}
}
}
+ handle_broken_image($img) {
+ const item_abbr = $($img).attr('alt');
+ $($img).parent().replaceWith(`<div class="item-image item-abbr">${item_abbr}</div>`);
+ }
+
scroll_to_item($item) {
if ($item.length === 0) return;
const scrollTop = $item.offset().top - this.$cart_items_wrapper.offset().top + this.$cart_items_wrapper.scrollTop();
diff --git a/erpnext/selling/page/point_of_sale/pos_item_details.js b/erpnext/selling/page/point_of_sale/pos_item_details.js
index 32a4556..df62696 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_details.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_details.js
@@ -54,13 +54,24 @@
this.$dicount_section = this.$component.find('.discount-section');
}
- toggle_item_details_section(item) {
- const { item_code, batch_no, uom } = this.current_item;
+ has_item_has_changed(item) {
+ const { item_code, batch_no, uom, rate } = this.current_item;
const item_code_is_same = item && item_code === item.item_code;
const batch_is_same = item && batch_no == item.batch_no;
const uom_is_same = item && uom === item.uom;
+ const rate_is_same = item && rate === item.rate;
+
+ if (!item)
+ return false;
- this.item_has_changed = !item ? false : item_code_is_same && batch_is_same && uom_is_same ? false : true;
+ if (item_code_is_same && batch_is_same && uom_is_same && rate_is_same)
+ return false;
+
+ return true;
+ }
+
+ toggle_item_details_section(item) {
+ this.item_has_changed = this.has_item_has_changed(item);
this.events.toggle_item_selector(this.item_has_changed);
this.toggle_component(this.item_has_changed);
@@ -72,11 +83,12 @@
this.item_row = item;
this.currency = this.events.get_frm().doc.currency;
- this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom };
+ this.current_item = { item_code: item.item_code, batch_no: item.batch_no, uom: item.uom, rate: item.rate };
this.render_dom(item);
this.render_discount_dom(item);
this.render_form(item);
+ this.events.highlight_cart_item(item);
} else {
this.validate_serial_batch_item();
this.current_item = {};
@@ -198,12 +210,14 @@
if (this.allow_rate_change) {
this.rate_control.df.onchange = function() {
if (this.value || flt(this.value) === 0) {
+ me.events.set_value_in_current_cart_item('rate', this.value);
me.events.form_updated(me.doctype, me.name, 'rate', this.value).then(() => {
const item_row = frappe.get_doc(me.doctype, me.name);
const doc = me.events.get_frm().doc;
me.$item_price.html(format_currency(item_row.rate, doc.currency));
me.render_discount_dom(item_row);
});
+ me.current_item.rate = this.value;
}
};
} else {
@@ -292,11 +306,7 @@
frappe.model.on("POS Invoice Item", "*", (fieldname, value, item_row) => {
const field_control = this[`${fieldname}_control`];
- const { item_code, batch_no, uom } = this.current_item;
- const item_code_is_same = item_code === item_row.item_code;
- const batch_is_same = batch_no == item_row.batch_no;
- const uom_is_same = uom === item_row.uom;
- const item_is_same = item_code_is_same && batch_is_same && uom_is_same ? true : false;
+ const item_is_same = !this.has_item_has_changed(item_row);
if (item_is_same && field_control && field_control.get_value() !== value) {
field_control.set_value(value);
diff --git a/erpnext/selling/page/point_of_sale/pos_item_selector.js b/erpnext/selling/page/point_of_sale/pos_item_selector.js
index b8a82a9..5b48725 100644
--- a/erpnext/selling/page/point_of_sale/pos_item_selector.js
+++ b/erpnext/selling/page/point_of_sale/pos_item_selector.js
@@ -78,7 +78,7 @@
get_item_html(item) {
const me = this;
// eslint-disable-next-line no-unused-vars
- const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom } = item;
+ const { item_image, serial_no, batch_no, barcode, actual_qty, stock_uom, price_list_rate } = item;
const indicator_color = actual_qty > 10 ? "green" : actual_qty <= 0 ? "red" : "orange";
let qty_to_display = actual_qty;
@@ -94,7 +94,11 @@
<span class="indicator-pill whitespace-nowrap ${indicator_color}">${qty_to_display}</span>
</div>
<div class="flex items-center justify-center h-32 border-b-grey text-6xl text-grey-100">
- <img class="h-full" src="${item_image}" alt="${frappe.get_abbr(item.item_name)}" style="object-fit: cover;">
+ <img
+ onerror="cur_pos.item_selector.handle_broken_image(this)"
+ class="h-full" src="${item_image}"
+ alt="${frappe.get_abbr(item.item_name)}"
+ style="object-fit: cover;">
</div>`;
} else {
return `<div class="item-qty-pill">
@@ -108,6 +112,7 @@
`<div class="item-wrapper"
data-item-code="${escape(item.item_code)}" data-serial-no="${escape(serial_no)}"
data-batch-no="${escape(batch_no)}" data-uom="${escape(stock_uom)}"
+ data-rate="${escape(price_list_rate)}"
title="${item.item_name}">
${get_item_image_html()}
@@ -116,12 +121,17 @@
<div class="item-name">
${frappe.ellipsis(item.item_name, 18)}
</div>
- <div class="item-rate">${format_currency(item.price_list_rate, item.currency, 0) || 0}</div>
+ <div class="item-rate">${format_currency(price_list_rate, item.currency, 0) || 0}</div>
</div>
</div>`
);
}
+ handle_broken_image($img) {
+ const item_abbr = $($img).attr('alt');
+ $($img).parent().replaceWith(`<div class="item-display abbr">${item_abbr}</div>`);
+ }
+
make_search_bar() {
const me = this;
const doc = me.events.get_frm().doc;
@@ -213,13 +223,15 @@
let batch_no = unescape($item.attr('data-batch-no'));
let serial_no = unescape($item.attr('data-serial-no'));
let uom = unescape($item.attr('data-uom'));
+ let rate = unescape($item.attr('data-rate'));
// escape(undefined) returns "undefined" then unescape returns "undefined"
batch_no = batch_no === "undefined" ? undefined : batch_no;
serial_no = serial_no === "undefined" ? undefined : serial_no;
uom = uom === "undefined" ? undefined : uom;
+ rate = rate === "undefined" ? undefined : rate;
- me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom }});
+ me.events.item_selected({ field: 'qty', value: "+1", item: { item_code, batch_no, serial_no, uom, rate }});
me.set_search_value('');
});
diff --git a/erpnext/support/doctype/issue/issue.json b/erpnext/support/doctype/issue/issue.json
index a43381c..bc29821 100644
--- a/erpnext/support/doctype/issue/issue.json
+++ b/erpnext/support/doctype/issue/issue.json
@@ -119,7 +119,7 @@
"no_copy": 1,
"oldfieldname": "status",
"oldfieldtype": "Select",
- "options": "Open\nReplied\nHold\nResolved\nClosed",
+ "options": "Open\nReplied\nOn Hold\nResolved\nClosed",
"search_index": 1
},
{
@@ -410,7 +410,7 @@
"icon": "fa fa-ticket",
"idx": 7,
"links": [],
- "modified": "2020-08-11 18:49:07.574769",
+ "modified": "2021-05-26 10:49:07.574769",
"modified_by": "Administrator",
"module": "Support",
"name": "Issue",
diff --git a/erpnext/support/report/issue_summary/issue_summary.js b/erpnext/support/report/issue_summary/issue_summary.js
index eb0e06c..a5122d0 100644
--- a/erpnext/support/report/issue_summary/issue_summary.js
+++ b/erpnext/support/report/issue_summary/issue_summary.js
@@ -42,6 +42,7 @@
"",
{label: __('Open'), value: 'Open'},
{label: __('Replied'), value: 'Replied'},
+ {label: __('On Hold'), value: 'On Hold'},
{label: __('Resolved'), value: 'Resolved'},
{label: __('Closed'), value: 'Closed'}
]
diff --git a/erpnext/support/report/issue_summary/issue_summary.py b/erpnext/support/report/issue_summary/issue_summary.py
index 7861e30..bba25b8 100644
--- a/erpnext/support/report/issue_summary/issue_summary.py
+++ b/erpnext/support/report/issue_summary/issue_summary.py
@@ -62,7 +62,7 @@
'width': 200
})
- self.statuses = ['Open', 'Replied', 'Resolved', 'Closed']
+ self.statuses = ['Open', 'Replied', 'On Hold', 'Resolved', 'Closed']
for status in self.statuses:
self.columns.append({
'label': _(status),
@@ -265,6 +265,7 @@
labels = []
open_issues = []
replied_issues = []
+ on_hold_issues = []
resolved_issues = []
closed_issues = []
@@ -277,6 +278,7 @@
labels.append(entry.get(entity_field))
open_issues.append(entry.get('open'))
replied_issues.append(entry.get('replied'))
+ on_hold_issues.append(entry.get('on_hold'))
resolved_issues.append(entry.get('resolved'))
closed_issues.append(entry.get('closed'))
@@ -293,6 +295,10 @@
'values': replied_issues[:30]
},
{
+ 'name': 'On Hold',
+ 'values': on_hold_issues[:30]
+ },
+ {
'name': 'Resolved',
'values': resolved_issues[:30]
},
@@ -313,12 +319,14 @@
open_issues = 0
replied = 0
+ on_hold = 0
resolved = 0
closed = 0
for entry in self.data:
open_issues += entry.get('open')
replied += entry.get('replied')
+ on_hold += entry.get('on_hold')
resolved += entry.get('resolved')
closed += entry.get('closed')
@@ -336,6 +344,12 @@
'datatype': 'Int',
},
{
+ 'value': on_hold,
+ 'indicator': 'Grey',
+ 'label': _('On Hold'),
+ 'datatype': 'Int',
+ },
+ {
'value': resolved,
'indicator': 'Green',
'label': _('Resolved'),