feat: complete R2 workflow - QA, pricing, sales
This commit is contained in:
@@ -0,0 +1,2 @@
|
||||
|
||||
from westech_r2.api import sales
|
||||
|
||||
+31
-4
@@ -3,9 +3,9 @@ from frappe import _
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_qa_ready_serials(limit=50):
|
||||
"""Get Serial Nos ready for QA (Erasure Complete state)."""
|
||||
"""Get Serial Nos ready for QA."""
|
||||
return frappe.get_all('Serial No',
|
||||
filters={'r2_status': 'Erasure Complete'},
|
||||
filters={'r2_status': 'Needs QA'},
|
||||
fields=['name', 'item_code', 'item_name', 'pallet', 'cosmetic_grade'],
|
||||
limit=limit,
|
||||
order_by='creation asc'
|
||||
@@ -19,11 +19,10 @@ def create_qa_from_serial(serial_no):
|
||||
|
||||
serial = frappe.get_doc('Serial No', serial_no)
|
||||
|
||||
# Check if already has active inspection
|
||||
existing = frappe.db.get_value('R2 Device Inspection',
|
||||
{'serial_no': serial_no, 'docstatus': ['!=', 2]}, 'name')
|
||||
if existing:
|
||||
return {'error': f'Inspection {existing} already exists for this serial'}
|
||||
return {'error': f'Inspection {existing} already exists'}
|
||||
|
||||
insp = frappe.get_doc({
|
||||
'doctype': 'R2 Device Inspection',
|
||||
@@ -39,3 +38,31 @@ def create_qa_from_serial(serial_no):
|
||||
insp.insert(ignore_permissions=True)
|
||||
|
||||
return {'success': True, 'inspection': insp.name}
|
||||
|
||||
@frappe.whitelist()
|
||||
def auto_grade(serial_no, grade='C5'):
|
||||
"""Auto-grade a device and move to Priced state."""
|
||||
serial = frappe.get_doc('Serial No', serial_no)
|
||||
serial.cosmetic_grade = grade
|
||||
serial.r2_status = 'Graded'
|
||||
serial.save(ignore_permissions=True)
|
||||
|
||||
# Apply flat pricing
|
||||
item = frappe.db.get_value('Item', serial.item_code, 'item_group')
|
||||
flat_prices = {
|
||||
'Laptops': {'c3': 250, 'c4': 200, 'c5': 150, 'c6': 100, 'c7': 60, 'c8': 30, 'c9': 15},
|
||||
'Desktops': {'c3': 180, 'c4': 150, 'c5': 120, 'c6': 80, 'c7': 50, 'c8': 25, 'c9': 10},
|
||||
'Tablets': {'c3': 120, 'c4': 100, 'c5': 80, 'c6': 50, 'c7': 30, 'c8': 15, 'c9': 8},
|
||||
'Phones': {'c3': 100, 'c4': 80, 'c5': 60, 'c6': 40, 'c7': 25, 'c8': 12, 'c9': 5}
|
||||
}
|
||||
prices = flat_prices.get(item, flat_prices['Laptops'])
|
||||
price = prices.get(grade.lower(), 100)
|
||||
|
||||
serial.suggested_price = price
|
||||
serial.assigned_price = price
|
||||
serial.pricing_status = 'Priced'
|
||||
serial.price_point = grade
|
||||
serial.r2_status = 'Priced'
|
||||
serial.save(ignore_permissions=True)
|
||||
|
||||
return {'success': True, 'price': price}
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
import frappe
|
||||
from frappe import _
|
||||
|
||||
@frappe.whitelist()
|
||||
def quick_sell(serial_no, customer=None, payment_method='Cash'):
|
||||
"""Create Sales Invoice for quick cash sale."""
|
||||
try:
|
||||
serial = frappe.get_doc('Serial No', serial_no)
|
||||
|
||||
if serial.r2_status != 'Ready for Sale':
|
||||
return {'error': 'Device must be Ready for Sale'}
|
||||
|
||||
# Use default customer if none provided
|
||||
if not customer:
|
||||
customer = frappe.db.get_value('Customer', {}, 'name', order_by='creation asc')
|
||||
if not customer:
|
||||
# Create walk-in customer
|
||||
customer = frappe.get_doc({
|
||||
'doctype': 'Customer',
|
||||
'customer_name': 'Walk-in Customer',
|
||||
'customer_type': 'Individual'
|
||||
}).insert(ignore_permissions=True).name
|
||||
|
||||
# Create Sales Invoice
|
||||
price = serial.assigned_price or serial.suggested_price or 0
|
||||
|
||||
invoice = frappe.get_doc({
|
||||
'doctype': 'Sales Invoice',
|
||||
'customer': customer,
|
||||
'serial_no': serial_no,
|
||||
'device_condition': f"Cosmetic: {serial.cosmetic_grade or 'N/A'}",
|
||||
'posting_date': frappe.utils.today(),
|
||||
'due_date': frappe.utils.today(),
|
||||
'items': [{
|
||||
'item_code': serial.item_code,
|
||||
'qty': 1,
|
||||
'rate': price,
|
||||
'amount': price,
|
||||
'serial_no': serial_no
|
||||
}],
|
||||
'payments': [{
|
||||
'mode_of_payment': payment_method,
|
||||
'amount': price
|
||||
}]
|
||||
})
|
||||
invoice.insert(ignore_permissions=True)
|
||||
invoice.submit()
|
||||
|
||||
# Update Serial No
|
||||
serial.r2_status = 'Sold'
|
||||
serial.status = 'Delivered'
|
||||
serial.customer = customer
|
||||
serial.save(ignore_permissions=True)
|
||||
|
||||
return {
|
||||
'success': True,
|
||||
'invoice': invoice.name,
|
||||
'customer': customer,
|
||||
'amount': price
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
frappe.log_error(f"Quick sell failed: {str(e)}", "Sales")
|
||||
return {'error': str(e)}
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_sales_order(quotation_name):
|
||||
"""Create Sales Order from Quotation."""
|
||||
try:
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_order
|
||||
|
||||
so = make_sales_order(quotation_name)
|
||||
so.insert(ignore_permissions=True)
|
||||
so.submit()
|
||||
|
||||
return {'success': True, 'sales_order': so.name}
|
||||
except Exception as e:
|
||||
return {'error': str(e)}
|
||||
|
||||
@frappe.whitelist()
|
||||
def create_delivery_note(sales_order_name):
|
||||
"""Create Delivery Note from Sales Order."""
|
||||
try:
|
||||
from erpnext.selling.doctype.sales_order.sales_order import make_delivery_note
|
||||
|
||||
dn = make_delivery_note(sales_order_name)
|
||||
dn.insert(ignore_permissions=True)
|
||||
dn.submit()
|
||||
|
||||
return {'success': True, 'delivery_note': dn.name}
|
||||
except Exception as e:
|
||||
return {'error': str(e)}
|
||||
Reference in New Issue
Block a user