frappe.pages['receiving'].on_page_load = function(wrapper) {
var page = frappe.ui.make_app_page({
parent: wrapper,
title: 'Receiving',
single_column: true
});
// Inline HTML — same pattern as intake.js
$(wrapper).find('.layout-main-section').html(`
🚛 Receiving
Schedule pickups, manage routes, and check in loads.
📅 Pickup Calendar — Next 30 Days
Date Weekday Type Customer Contact Address Est. Items Data RED/R2 Status Notes Truck AoR CoD
Loading...
+ Check In Load 📋 CoR Report
Recent Check-ins
Date Customer Type Actual Pallets Actual Weight Load Contents Data Status RED/R2 Status
Loading...
`);
// ── Stage Tabs ──
$("#receiving-tabs a").on("click", function(e) {
e.preventDefault();
$(this).tab("show");
var stage = $(this).attr("href").replace("#stage-", "");
if (stage === "a") loadPickups();
if (stage === "b") loadRoutes();
if (stage === "c") loadCheckins();
});
// ── Stage A: Link Controls ──
var customer_control = null;
function setupCustomerLink() {
customer_control = frappe.ui.form.make_control({
parent: $("#sp-customer-control"),
df: {
fieldtype: "Link",
fieldname: "customer_number",
options: "Customer",
label: "Customer",
reqd: 1,
placeholder: "Search customer...",
onchange: function() {
var val = customer_control.get_value();
if (val) fetchCustomerDetails(val);
else clearCustomerFields();
}
},
only_input: true,
});
customer_control.refresh();
$("#sp-customer-control .control-input").css("margin", "0");
$("#sp-customer-control .help-box").remove();
}
function fetchCustomerDetails(customer_name) {
frappe.call({
method: "frappe.client.get",
args: { doctype: "Customer", name: customer_name },
callback: function(r) {
if (!r.message) return;
var c = r.message;
$("#sp-company_name").val(c.customer_name || "");
$("#sp-contact_name").val(c.contact_name || "");
$("#sp-contact_phone").val(c.contact_phone || "");
$("#sp-contact_email").val(c.contact_email || "");
$("#sp-legacy_notes").val(c.legacy_notes || "");
$("#sp-hours_of_operation").val(c.hours_of_operation || "");
frappe.call({
method: "frappe.client.get_list",
args: {
doctype: "Address",
filters: [["Dynamic Link", "link_name", "=", customer_name]],
fields: ["address_line1", "city", "state", "pincode"],
limit_page_length: 1
},
callback: function(ra) {
if (ra.message && ra.message.length) {
var a = ra.message[0];
$("#sp-address_line").val(a.address_line1 || "");
$("#sp-city").val(a.city || "");
$("#sp-state").val(a.state || "AZ");
$("#sp-zip_code").val(a.pincode || "");
}
}
});
frappe.call({
method: "frappe.client.get_list",
args: {
doctype: "Contact",
filters: [["Dynamic Link", "link_name", "=", customer_name]],
fields: ["first_name", "last_name", "email_id", "phone", "mobile_no"],
limit_page_length: 1
},
callback: function(rc) {
if (rc.message && rc.message.length) {
var ct = rc.message[0];
if (!$("#sp-contact_name").val()) {
$("#sp-contact_name").val((ct.first_name || "") + " " + (ct.last_name || ""));
}
if (!$("#sp-contact_phone").val()) {
$("#sp-contact_phone").val(ct.phone || ct.mobile_no || "");
}
if (!$("#sp-contact_email").val()) {
$("#sp-contact_email").val(ct.email_id || "");
}
}
}
});
}
});
}
function clearCustomerFields() {
$("#sp-company_name, #sp-contact_name, #sp-contact_phone, #sp-contact_email, #sp-address_line, #sp-city, #sp-state, #sp-zip_code, #sp-legacy_notes, #sp-hours_of_operation").val("");
$("#sp-state").val("AZ");
}
// ── Stage A: Load Pickups ──
function loadPickups() {
var dateFilter = $("#pickup-date-filter").val();
frappe.call({
method: "westech_r2.api.receiving_api.get_pickups",
args: { date: dateFilter },
callback: function(r) {
if (r.message) {
renderPickupTable(r.message.pickups || []);
renderCalendar(r.message.calendar || []);
// weekly chart removed
$("#pickup-count-label").text((r.message.pickups || []).length + " pickups");
}
}
});
}
function renderPickupTable(pickups) {
var tbody = $("#pickup-tbody");
if (!pickups.length) {
tbody.html('No scheduled pickups ');
return;
}
var statusColors = { "Scheduled": "#2196F3", "Routed": "#009688", "In Progress": "#FF9800", "Complete": "#4CAF50", "Cancelled": "#F44336" };
var h = "";
pickups.forEach(function(p) {
var st = p.status || "Scheduled";
var sc = statusColors[st] || "#999";
var weekday = p.pickup_date ? dayName(new Date(p.pickup_date + "T12:00:00")) : "";
var typeBadge = p.pickup_type === "Drop-off"
? 'Drop-off '
: 'Pickup ';
h += '';
h += '' + esc(p.pickup_date || "") + ' ';
h += '' + weekday + ' ';
h += '' + typeBadge + ' ';
h += '' + esc(p.company_name || p.customer_number || "") + ' ';
h += '' + esc((p.contact_name || "") + (p.contact_phone ? " • " + p.contact_phone : "")) + ' ';
h += '' + esc((p.address_line || "") + (p.city ? ", " + p.city : "")) + ' ';
h += '' + (p.estimated_items || "—") + ' ';
h += '' + esc(p.data_status || "—") + ' ';
h += '' + esc(p.red_r2 || "—") + ' ';
h += '' + esc(st) + ' ';
h += '' + esc(p.notes || "") + ' ';
h += '' + esc(p.truck || "—") + ' ';
h += '' + (p.needs_aor ? "✓" : "") + ' ';
h += '' + (p.needs_cod ? "✓" : "") + ' ';
h += ' ';
});
tbody.html(h);
}
function renderCalendar(days) {
var el = $("#pickup-calendar");
if (!days || !days.length) { el.html('No upcoming pickups
'); return; }
var today = frappe.datetime.nowdate();
var h = '';
["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].forEach(function(d) {
h += '
' + d + '
';
});
var first = new Date(days[0].date + "T12:00:00");
for (var i = 0; i < first.getDay(); i++) h += '
';
days.forEach(function(d) {
var isToday = d.date === today;
var hasCount = d.count > 0;
var bg = isToday ? "cal-day today" : (hasCount ? "cal-day has-pickups" : "cal-day");
var onclick = hasCount ? "onclick=$('#pickup-date-filter').val('" + d.date + "');loadPickups();" : "";
h += '
';
h += '
' + d.date.split("-")[2] + '
';
if (hasCount) h += '
' + d.count + '
';
h += '
';
});
h += '
';
el.html(h);
}
// ── Stage A: New Pickup ──
$("#btn-new-pickup").on("click", function() {
$("#new-pickup-form").show();
$("#sp-pickup_date").val(frappe.datetime.nowdate());
setupCustomerLink();
});
$("#btn-cancel-pickup").on("click", function() {
$("#new-pickup-form").hide();
if (customer_control) customer_control.set_value("");
});
$("#pickup-form").on("submit", function(e) {
e.preventDefault();
var doc = {
doctype: "Scheduled Pickup",
pickup_date: $("#sp-pickup_date").val(),
pickup_type: $("#sp-pickup_type").val(),
customer_number: customer_control ? customer_control.get_value() : "",
company_name: $("#sp-company_name").val(),
contact_name: $("#sp-contact_name").val(),
contact_phone: $("#sp-contact_phone").val(),
contact_email: $("#sp-contact_email").val(),
address_line: $("#sp-address_line").val(),
city: $("#sp-city").val(),
state: $("#sp-state").val(),
zip_code: $("#sp-zip_code").val(),
estimated_items: parseInt($("#sp-estimated_items").val()) || 0,
estimated_weight: $("#sp-estimated_weight").val(),
load_contents: $("#sp-load_contents").val(),
data_status: $("#sp-data_status").val(),
red_r2: $("#sp-red_r2").val(),
needs_aor: $("#sp-needs_aor").is(":checked") ? 1 : 0,
needs_cod: $("#sp-needs_cod").is(":checked") ? 1 : 0,
notes: $("#sp-notes").val(),
legacy_notes: $("#sp-legacy_notes").val(),
status: "Scheduled"
};
frappe.call({
method: "frappe.client.insert",
args: { doc: doc },
callback: function(r) {
if (r.message) {
frappe.show_alert({ message: "Pickup scheduled", indicator: "green" });
$("#new-pickup-form").hide();
loadPickups();
}
}
});
});
$("#pickup-date-filter").on("change", loadPickups);
$("#btn-clear-date").on("click", function() {
$("#pickup-date-filter").val("");
loadPickups();
});
// ── Stage B: Routing ──
function loadRoutes() {
var date = $("#route-date").val() || frappe.datetime.nowdate();
$("#route-date").val(date);
frappe.call({
method: "westech_r2.api.receiving_api.get_pickups",
args: { date: date },
callback: function(r) {
if (r.message) renderRouteColumns(r.message.pickups || []);
}
});
}
function renderRouteColumns(pickups) {
var trucks = { "Truck 1": [], "Truck 2": [], "Truck 3": [], "Unassigned": [] };
pickups.forEach(function(p) {
var t = p.truck || "";
if (t && trucks[t]) trucks[t].push(p);
else trucks["Unassigned"].push(p);
});
["Truck 1", "Truck 2", "Truck 3"].forEach(function(t) {
var key = t.toLowerCase().replace(/ /g, "");
$("#" + key + "-count").text("(" + trucks[t].length + " stops)");
$("#" + key + "-stops").html(trucks[t].map(function(p, i) { return stopCard(p, i + 1); }).join(""));
});
$("#unassigned-count").text("(" + trucks["Unassigned"].length + " stops)");
$("#unassigned-stops").html(trucks["Unassigned"].map(function(p) { return stopCard(p, 0); }).join(""));
}
function stopCard(p, order) {
var h = '';
if (order) h += '
Stop #' + order + '
';
h += '
' + esc(p.company_name || p.customer_number || "Unknown") + '
';
h += '
' + esc((p.address_line || "") + (p.city ? ", " + p.city : "")) + '
';
h += '
';
if (p.estimated_items) h += '' + p.estimated_items + ' items ';
if (p.data_status) h += '' + esc(p.data_status) + ' ';
if (p.red_r2) h += '' + esc(p.red_r2) + ' ';
if (p.needs_aor) h += 'AoR ';
if (p.needs_cod) h += 'CoD ';
h += '
';
return h;
}
$("#btn-load-routes").on("click", loadRoutes);
$("#btn-auto-route").on("click", function() {
var date = $("#route-date").val();
if (!date) { frappe.msgprint("Select a date first"); return; }
frappe.call({
method: "westech_r2.api.receiving_api.auto_route",
args: { date: date },
callback: function(r) {
if (r.message && r.message.success) {
frappe.show_alert({ message: "Routes optimized", indicator: "green" });
loadRoutes();
}
}
});
});
$("#btn-route-sheet").on("click", function() {
var date = $("#route-date").val() || frappe.datetime.nowdate();
window.open("/api/method/westech_r2.api.receiving_api.print_route_sheet?date=" + date, "_blank");
});
$("#btn-green-sheet").on("click", function() {
var date = $("#route-date").val() || frappe.datetime.nowdate();
window.open("/api/method/westech_r2.api.receiving_api.print_green_sheet?date=" + date, "_blank");
});
$("#btn-labels").on("click", function() {
var date = $("#route-date").val() || frappe.datetime.nowdate();
window.open("/api/method/westech_r2.api.receiving_api.print_labels?date=" + date, "_blank");
});
// ── Stage C: Check-in ──
var checkin_pickup_control = null;
function loadCheckins() {
frappe.call({
method: "westech_r2.api.receiving_api.get_checkins",
callback: function(r) {
if (r.message) renderCheckinTable(r.message.checkins || []);
}
});
}
function renderCheckinTable(checkins) {
var tbody = $("#checkin-tbody");
if (!checkins.length) {
tbody.html('No check-ins yet ');
return;
}
tbody.html(checkins.map(function(c) {
return '' + esc(c.pickup_date || "") + ' ' +
'' + esc(c.company_name || "") + ' ' +
'' + esc(c.pickup_type || "") + ' ' +
'' + (c.estimated_items || "—") + ' ' +
'' + (c.estimated_weight || "—") + ' ' +
'' + esc(c.load_contents || "") + ' ' +
'' + esc(c.data_status || "—") + ' ' +
'' + esc(c.red_r2 || "—") + ' ' +
'' + esc(c.status || "") + ' ';
}).join(""));
}
$("#btn-new-checkin").on("click", function() {
$("#checkin-form").show();
$("#ci-received_date").val(frappe.datetime.nowdate());
checkin_pickup_control = frappe.ui.form.make_control({
parent: $("#ci-pickup-control"),
df: {
fieldtype: "Link",
fieldname: "pickup_ref",
options: "Scheduled Pickup",
label: "Scheduled Pickup",
reqd: 1,
placeholder: "Search pickup...",
get_query: function() {
return {
filters: [
["Scheduled Pickup", "status", "in", ["Scheduled", "Routed", "In Progress"]]
]
};
}
},
only_input: true,
});
checkin_pickup_control.refresh();
$("#ci-pickup-control .control-input").css("margin", "0");
$("#ci-pickup-control .help-box").remove();
});
$("#btn-cancel-checkin").on("click", function() {
$("#checkin-form").hide();
});
$("#checkin-form-inner").on("submit", function(e) {
e.preventDefault();
var pickupName = checkin_pickup_control ? checkin_pickup_control.get_value() : "";
if (!pickupName) { frappe.msgprint("Select a pickup"); return; }
var update = {};
update.status = "Complete";
if ($("#ci-actual_pallets").val()) update.estimated_items = parseInt($("#ci-actual_pallets").val());
if ($("#ci-actual_weight").val()) update.estimated_weight = $("#ci-actual_weight").val();
if ($("#ci-load_contents").val()) update.load_contents = $("#ci-load_contents").val();
frappe.call({
method: "frappe.client.set_value",
args: {
doctype: "Scheduled Pickup",
name: pickupName,
fieldname: update
},
callback: function(r) {
if (r.message) {
frappe.show_alert({ message: "Load checked in", indicator: "green" });
$("#checkin-form").hide();
loadCheckins();
}
}
});
});
$("#btn-cor-report").on("click", function() {
window.open("/api/method/westech_r2.api.receiving_api.cor_report", "_blank");
});
// ── Helpers ──
function esc(s) { return s ? String(s).replace(/&/g, "&").replace(//g, ">").replace(/"/g, """) : ""; }
function dayName(d) { return ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"][d.getDay()]; }
// ── Init ──
loadPickups();
};