added win loss in sales invoice

This commit is contained in:
Ali 2025-09-01 20:38:51 +04:00
parent b032b6fb85
commit c1029e14f4
2 changed files with 182 additions and 8 deletions

View File

@ -125,6 +125,123 @@ def create_custom_fields():
insert_after='is_paid', insert_after='is_paid',
hidden=0 hidden=0
), ),
# Hidden field to fetch company main activity
dict(
fieldname='company_main_activity',
label='Company Main Activity',
fieldtype='Data',
insert_after='is_taxes_doc',
hidden=1,
fetch_from='company.main_activity',
read_only=1
),
# Organizer and Seller checkboxes
dict(
fieldname='organizer',
label='Organizer',
fieldtype='Check',
insert_after='is_debit_note',
depends_on='eval:doc.company_main_activity && ["92000", "9200003", "9200004", "9200001", "9200002", "9200005"].includes(doc.company_main_activity)',
allow_on_submit=1
),
dict(
fieldname='seller',
label='Seller',
fieldtype='Check',
insert_after='organizer',
depends_on='eval:doc.company_main_activity && ["92000", "9200003", "9200004", "9200001", "9200002", "9200005"].includes(doc.company_main_activity)',
allow_on_submit=1
),
# Won and Lost checkboxes after section_break_42 (в ряд)
dict(
fieldname='won_lost_html',
fieldtype='HTML',
insert_after='section_break_42',
depends_on='eval:doc.company_main_activity && ["92000", "9200003", "9200004", "9200001", "9200002", "9200005"].includes(doc.company_main_activity)',
options="""
<div style="display: flex; gap: 20px; margin: 8px 0;">
<label style="display: flex; align-items: center; gap: 5px;">
<input type="checkbox" class="won-checkbox" checked style="margin: 0;">
<span>Won</span>
</label>
<label style="display: flex; align-items: center; gap: 5px;">
<input type="checkbox" class="lost-checkbox" style="margin: 0;">
<span>Lost</span>
</label>
</div>
<script>
(function() {
// Ждем полной загрузки страницы и инициализации Frappe
setTimeout(function() {
if (typeof frappe === 'undefined' || !cur_frm) {
// Если Frappe еще не готов, ждем еще
setTimeout(arguments.callee, 500);
return;
}
const wonCheckbox = document.querySelector('.won-checkbox');
const lostCheckbox = document.querySelector('.lost-checkbox');
if (!wonCheckbox || !lostCheckbox) return;
// Синхронизация с текущими значениями полей
wonCheckbox.checked = cur_frm.doc.won ? true : false;
lostCheckbox.checked = cur_frm.doc.lost ? true : false;
// Обеспечиваем что всегда выбрана одна галочка
if (!wonCheckbox.checked && !lostCheckbox.checked) {
wonCheckbox.checked = true;
cur_frm.set_value('won', 1);
}
wonCheckbox.addEventListener('change', function() {
if (this.checked) {
lostCheckbox.checked = false;
cur_frm.set_value('lost', 0);
cur_frm.set_value('won', 1);
} else {
lostCheckbox.checked = true;
cur_frm.set_value('lost', 1);
cur_frm.set_value('won', 0);
}
});
lostCheckbox.addEventListener('change', function() {
if (this.checked) {
wonCheckbox.checked = false;
cur_frm.set_value('won', 0);
cur_frm.set_value('lost', 1);
} else {
wonCheckbox.checked = true;
cur_frm.set_value('won', 1);
cur_frm.set_value('lost', 0);
}
});
}, 1000); // Даем время на инициализацию Frappe
})();
</script>
"""
),
# Скрытые поля для хранения значений
dict(
fieldname='won',
label='Won',
fieldtype='Check',
insert_after='won_lost_html',
hidden=1,
default=1,
allow_on_submit=1
),
dict(
fieldname='lost',
label='Lost',
fieldtype='Check',
insert_after='won',
hidden=1,
default=0,
allow_on_submit=1
),
# New comments section after time_sheet_list # New comments section after time_sheet_list
dict( dict(
fieldname='comments_section', fieldname='comments_section',
@ -789,24 +906,30 @@ def create_custom_fields():
for doctype, fields in custom_fields.items(): for doctype, fields in custom_fields.items():
for field in fields: for field in fields:
# Check if fieldname exists before processing # Проверяем наличие fieldname перед обработкой
if 'fieldname' not in field: if 'fieldname' not in field:
print(f"Skipping field without fieldname in {doctype}: {field}") print(f"Skipping field without fieldname in {doctype}: {field}")
continue continue
# Check if field already exists # Удаление существующего поля, если оно уже есть
if frappe.db.exists("Custom Field", {"dt": doctype, "fieldname": field['fieldname']}): if frappe.db.exists("Custom Field", {"dt": doctype, "fieldname": field['fieldname']}):
print(f"Field {field['fieldname']} already exists in {doctype}, skipping...") try:
continue custom_field_name = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": field['fieldname']}, "name")
frappe.delete_doc("Custom Field", custom_field_name)
# Create field only if it doesn't exist yet frappe.db.commit()
print(f"Deleted field {field['fieldname']} in {doctype}")
except Exception as e:
print(f"Failed to delete field {field['fieldname']} in {doctype}: {e}")
# Создание нового поля
try: try:
create_custom_field(doctype, field) create_custom_field(doctype, field)
print(f"Created field {field['fieldname']} in {doctype}") print(f"Created field {field['fieldname']} in {doctype}")
except Exception as e: except Exception as e:
print(f"Failed to create field {field['fieldname']} in {doctype}: {e}") print(f"Failed to create field {field['fieldname']} in {doctype}: {e}")
# Register the calculation hook for existing Sales Invoices # Коммит всех изменений
frappe.db.commit()
print("Setting up VAT calculation hooks...") print("Setting up VAT calculation hooks...")
create_custom_fields() create_custom_fields()

View File

@ -1,2 +1,53 @@
// Запускаем логику калькулятора НДС для Sales Invoice // Запускаем логику калькулятора НДС для Sales Invoice
jey_erp.vat_calculator.init('Sales Invoice'); jey_erp.vat_calculator.init('Sales Invoice');
// Объединенная логика для Sales Invoice
frappe.ui.form.on('Sales Invoice', {
refresh: function(frm) {
// Убедимся что одна из галочек won/lost всегда выбрана при загрузке формы
if (!frm.doc.won && !frm.doc.lost) {
frm.set_value('won', 1);
}
// Убедимся что хотя бы одна из галочек organizer/seller всегда выбрана при загрузке формы
if (!frm.doc.organizer && !frm.doc.seller) {
frm.set_value('organizer', 1);
}
},
won: function(frm) {
if (frm.doc.won) {
// Если Won выбрана, снимаем Lost
frm.set_value('lost', 0);
} else {
// Если Won снята, автоматически ставим Lost
frm.set_value('lost', 1);
}
},
lost: function(frm) {
if (frm.doc.lost) {
// Если Lost выбрана, снимаем Won
frm.set_value('won', 0);
} else {
// Если Lost снята, автоматически ставим Won
frm.set_value('won', 1);
}
},
organizer: function(frm) {
// Если пытаются выключить organizer, но seller уже выключена - не позволяем
if (!frm.doc.organizer && !frm.doc.seller) {
frappe.msgprint(__('At least one option (Organizer or Seller) must be selected'));
frm.set_value('organizer', 1);
}
},
seller: function(frm) {
// Если пытаются выключить seller, но organizer уже выключена - не позволяем
if (!frm.doc.seller && !frm.doc.organizer) {
frappe.msgprint(__('At least one option (Organizer or Seller) must be selected'));
frm.set_value('seller', 1);
}
}
});