Hi Everyone,
i have managed to create some scripts that have seamlessly worked for me regarding the Gate Pass and Gate Inward System. Here the following scripts that i have used for gate pass and inward system:
----- gate inward client script---------
frappe.ui.form.on(‘Gate Inward’, {
returnable_gate_pass: function(frm) {
if (frm.doc.returnable_gate_pass) {
frappe.call({
method: ‘frappe.client.get’,
args: {
doctype: ‘Gate Pass’,
name: frm.doc.returnable_gate_pass
},
callback: function(r) {
if (r.message) {
// Get existing item codes to avoid duplicates
let existing_items = frm.doc.gate_inward_item.map(item => item.item_code);
r.message.gate_pass_item.forEach(item => {
// Only add if item doesn't exist AND has remaining balance
if (!existing_items.includes(item.item_code) &&
(item.balance > 0 || item.balance_2 > 0)) {
let row = frm.add_child('gate_inward_item');
row.item_group = item.item_group;
row.item_code = item.item_code;
row.item_name = item.item_name;
row.quantity = item.quantity;
row.quantity_2 = item.quantity_2;
row.uom = item.uom;
row.balance = item.balance;
row.balance_2 = item.balance_2;
row.returned_quantity = 0;
row.returned_quantity_2 = 0;
}
});
frm.refresh_field('gate_inward_item');
// Show message if no items were added
if (!r.message.gate_pass_item.some(item =>
(item.balance > 0 || item.balance_2 > 0) &&
!existing_items.includes(item.item_code))) {
frappe.msgprint(__('No items with remaining balance found in the selected Gate Pass'));
}
}
}
});
}
}
});
frappe.ui.form.on(‘Gate Pass Item’, {
returned_quantity: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
// Only validate if this item is part of the gate pass
if (frm.doc.returnable_gate_pass && row.balance) {
if (row.returned_quantity > row.balance) {
row.returned_quantity = row.balance;
frappe.msgprint((‘Returned quantity cannot exceed balance quantity’));
frm.refresh_field(‘gate_inward_item’);
}
}
},
returned_quantity_2: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
// Only validate if this item is part of the gate pass
if (frm.doc.returnable_gate_pass && row.balance_2) {
if (row.returned_quantity_2 > row.balance_2) {
row.returned_quantity_2 = row.balance_2;
frappe.msgprint((‘Returned quantity 2 cannot exceed balance quantity 2’));
frm.refresh_field(‘gate_inward_item’);
}
}
}
});
-------------- gate pass returnable status ---------------
frappe.ui.form.on(‘Gate Pass’, {
is_returnable: function(frm) {
if (frm.doc.is_returnable) {
frm.doc.gate_pass_item.forEach(item => {
item.balance = item.quantity;
item.balance_2 = item.quantity_2;
item.returned_quantity = 0;
item.returned_quantity_2 = 0;
});
frm.refresh_field(‘gate_pass_item’);
}
}
});
frappe.ui.form.on(‘Gate Pass Item’, {
quantity: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
if (frm.doc.is_returnable) {
row.balance = row.quantity;
row.returned_quantity = 0;
frm.refresh_field(‘gate_pass_item’);
}
},
quantity_2: function(frm, cdt, cdn) {
let row = locals[cdt][cdn];
if (frm.doc.is_returnable) {
row.balance_2 = row.quantity_2;
row.returned_quantity_2 = 0;
frm.refresh_field(‘gate_pass_item’);
}
}
});
-------------- gate inward server script (After Save)------------
if doc.returnable_gate_pass:
gate_pass = frappe.get_doc(“Gate Pass”, doc.returnable_gate_pass)
# Get list of items in gate pass
gate_pass_items = {item.item_code: item for item in gate_pass.gate_pass_item}
# Update balances for each item that exists in gate pass
for inward_item in doc.gate_inward_item:
if inward_item.item_code in gate_pass_items:
gp_item = gate_pass_items[inward_item.item_code]
if inward_item.returned_quantity > 0:
gp_item.balance = gp_item.balance - inward_item.returned_quantity
gp_item.returned_quantity = gp_item.returned_quantity + inward_item.returned_quantity
if inward_item.returned_quantity_2 > 0:
gp_item.balance_2 = gp_item.balance_2 - inward_item.returned_quantity_2
gp_item.returned_quantity_2 = gp_item.returned_quantity_2 + inward_item.returned_quantity_2
# Check if ALL items in gate pass are fully returned
all_items_returned = True
for gp_item in gate_pass.gate_pass_item:
if gp_item.balance > 0 or gp_item.balance_2 > 0:
all_items_returned = False
break
# Update Gate Pass status
current_date = str(frappe.utils.today())
if all_items_returned:
gate_pass.custom_status = "Returned"
elif gate_pass.return_date and str(gate_pass.return_date) < current_date:
gate_pass.custom_status = "Not Returned"
else:
gate_pass.custom_status = "To Return"
gate_pass.save(ignore_permissions=True)
----------- gate inwarrd server script (Before Save)-----------
if doc.returnable_gate_pass:
gate_pass = frappe.get_doc(“Gate Pass”, doc.returnable_gate_pass)
gate_pass_items = {item.item_code: item for item in gate_pass.gate_pass_item}
# Validate returned quantities only for items that exist in gate pass
for inward_item in doc.gate_inward_item:
if inward_item.item_code in gate_pass_items:
gp_item = gate_pass_items[inward_item.item_code]
if inward_item.returned_quantity > gp_item.balance:
frappe.throw(
f"Returned quantity ({inward_item.returned_quantity}) cannot exceed balance quantity ({gp_item.balance}) for item {inward_item.item_code}"
)
if inward_item.returned_quantity_2 > gp_item.balance_2:
frappe.throw(
f"Returned quantity 2 ({inward_item.returned_quantity_2}) cannot exceed balance quantity 2 ({gp_item.balance_2}) for item {inward_item.item_code}"
)
------------ gate inward server script (Before Delete)----------------
if doc.returnable_gate_pass:
gate_pass = frappe.get_doc(“Gate Pass”, doc.returnable_gate_pass)
# Restore balances
for inward_item in doc.gate_inward_item:
for gp_item in gate_pass.gate_pass_item:
if (inward_item.item_code == gp_item.item_code):
if inward_item.returned_quantity > 0:
gp_item.balance = gp_item.balance + inward_item.returned_quantity
gp_item.returned_quantity = gp_item.returned_quantity - inward_item.returned_quantity
if inward_item.returned_quantity_2 > 0:
gp_item.balance_2 = gp_item.balance_2 + inward_item.returned_quantity_2
gp_item.returned_quantity_2 = gp_item.returned_quantity_2 - inward_item.returned_quantity_2
# Update status based on current balance
all_items_pending = all(item.balance == item.quantity and item.balance_2 == item.quantity_2
for item in gate_pass.gate_pass_item)
current_date = str(frappe.utils.today())
if all_items_pending:
if gate_pass.return_date and str(gate_pass.return_date) < current_date:
gate_pass.custom_status = "Not Returned"
else:
gate_pass.custom_status = "To Return"
gate_pass.save(ignore_permissions=True)
now i am trying to make a reconciliation system where the subcontracted items are marked as returnables and returns in either different form, quality or units.
One may argue that such features are not necessary, but where i come from, Gate Pass System has become a part of security measures taken to avoid any risks. and especially since it was a demand from one of our clients.
any further insight will be deeply appreciated.
Regards,
Muhammad Shouib Saeed