invoice_az/MIGRATION_GUIDE.md

329 lines
8.3 KiB
Markdown

# Migration Guide: Tax Template to Tax Type
## Overview
This guide explains how to migrate existing Purchase Invoices from the old `item_tax_template` system to the new `tax_type` field.
---
## Background
**Before:** Agricultural purchase invoices used `item_tax_template` field to determine tax rates:
- "ƏDV 0%" → 0% VAT
- "ƏDV-dən azadolma" → 0% VAT (exempt)
- "ƏDV 2% cəlb" → 5% tax
**After:** Agricultural purchase invoices now use `tax_type` field:
- "Tax Free" → 0% VAT
- "Taxable" → 5% tax
---
## Who Needs to Migrate?
You need to migrate if you have:
- Purchase Invoices with `agricultural_goods = True`
- Items with `item_tax_template` set
- Items with `tax_type` = None (empty)
---
## Migration Options
### Option 1: Manual Migration (Recommended for Few Documents)
For each Purchase Invoice:
1. Open the document in edit mode
2. Check if `agricultural_goods` is checked
3. For each item in the items table:
- Look at the old `item_tax_template` value
- Set new `tax_type` based on mapping:
- If template is "ƏDV 2% cəlb" → select **"Taxable"**
- If template is anything else → select **"Tax Free"**
4. Save the document
5. `agricultural_tax_amount` will calculate automatically
### Option 2: Bulk Migration Script (For Many Documents)
Run this script in bench console:
```python
import frappe
def migrate_tax_templates_to_tax_type():
"""
Migrate item_tax_template values to tax_type for agricultural invoices
Mapping:
- "ƏDV 2% cəlb" → "Taxable" (5% tax)
- All others → "Tax Free" (0% VAT)
"""
# Get all agricultural purchase invoices (exclude cancelled)
invoices = frappe.get_all(
"Purchase Invoice",
filters={
"agricultural_goods": 1,
"docstatus": ["<", 2] # Draft or Submitted
},
fields=["name", "docstatus"]
)
print(f"\nFound {len(invoices)} agricultural purchase invoices")
print("="*60)
migrated_count = 0
skipped_count = 0
for inv in invoices:
doc = frappe.get_doc("Purchase Invoice", inv.name)
modified = False
for item in doc.items:
# Skip if tax_type already set
if item.tax_type:
continue
# Only migrate if item_tax_template exists
if not item.item_tax_template:
continue
# Map template to tax_type
if item.item_tax_template == "ƏDV 2% cəlb":
item.tax_type = "Taxable"
# Calculate 5% tax
item.agricultural_tax_amount = item.amount * 0.05
else:
# ƏDV 0%, ƏDV-dən azadolma, etc.
item.tax_type = "Tax Free"
item.agricultural_tax_amount = 0
modified = True
if modified:
try:
# For submitted documents, allow update
if doc.docstatus == 1:
doc.flags.ignore_validate_update_after_submit = True
doc.save()
migrated_count += 1
print(f"✓ Migrated: {doc.name} ({len(doc.items)} items)")
except Exception as e:
print(f"✗ Error migrating {doc.name}: {str(e)}")
else:
skipped_count += 1
print(f"⊘ Skipped: {doc.name} (no items to migrate)")
print("="*60)
print(f"\nMigration Complete:")
print(f" - Migrated: {migrated_count}")
print(f" - Skipped: {skipped_count}")
print(f" - Total: {len(invoices)}")
print()
# Run the migration
migrate_tax_templates_to_tax_type()
```
**How to run:**
```bash
cd /home/frappe/frappe-bench
bench --site site1 console
# Paste the script above, then press Enter
```
---
## Migration Mapping Table
| Old Item Tax Template | New Tax Type | Tax Amount Calculation |
|-----------------------|--------------|------------------------|
| ƏDV 0% | Tax Free | 0% (no tax) |
| ƏDV-dən azadolma | Tax Free | 0% (no tax) |
| ƏDV 2% cəlb | Taxable | 5% of amount |
| (empty) | Tax Free | 0% (default) |
| Any other | Tax Free | 0% (safe default) |
---
## Pre-Migration Checklist
- [ ] Backup your database: `bench --site site1 backup`
- [ ] Test the migration script on a single document first
- [ ] Verify the mapping is correct for your use case
- [ ] Note: Cancelled documents (docstatus = 2) are NOT migrated
---
## Post-Migration Verification
After migration, verify:
1. **Check migrated documents:**
```python
import frappe
# Get sample migrated document
doc = frappe.get_doc("Purchase Invoice", "ACC-PINV-2026-XXXXX")
for item in doc.items:
print(f"Item: {item.item_code}")
print(f" Old: {item.item_tax_template}")
print(f" New: {item.tax_type}")
print(f" Tax: {item.agricultural_tax_amount}")
print()
```
2. **Check counts:**
```python
import frappe
# Count items with tax_type set
result = frappe.db.sql("""
SELECT
tax_type,
COUNT(*) as count
FROM `tabPurchase Invoice Item`
WHERE parent IN (
SELECT name
FROM `tabPurchase Invoice`
WHERE agricultural_goods = 1
AND docstatus < 2
)
GROUP BY tax_type
""", as_dict=True)
for row in result:
print(f"{row.tax_type or '(empty)'}: {row.count} items")
```
3. **Test E-Taxes sending:**
- Open a migrated Purchase Invoice
- Verify buttons are visible (if agricultural_goods = True)
- Try sending to E-Taxes
- Confirm payload is correct
---
## Rollback Plan
If migration causes issues, you can:
1. **Restore from backup:**
```bash
bench --site site1 restore /path/to/backup.sql.gz
```
2. **Clear tax_type manually:**
```python
import frappe
frappe.db.sql("""
UPDATE `tabPurchase Invoice Item`
SET tax_type = NULL, agricultural_tax_amount = 0
WHERE parent IN (
SELECT name
FROM `tabPurchase Invoice`
WHERE agricultural_goods = 1
)
""")
frappe.db.commit()
```
---
## FAQ
### Q: Will old documents still work without migration?
**A:** Yes, but:
- Buttons will be hidden if `agricultural_goods = False`
- You must manually set `tax_type` before sending to E-Taxes
- Validation will fail if `tax_type` is empty
### Q: Do I need to migrate cancelled documents?
**A:** No, cancelled documents (docstatus = 2) don't need migration.
### Q: What happens to the old `item_tax_template` field?
**A:** It's still there but no longer used by E-Taxes integration. You can keep it for reference.
### Q: Can I delete `item_tax_template` after migration?
**A:** No! Other parts of ERPNext may use it. Only the E-Taxes integration uses `tax_type`.
### Q: What if I have custom tax templates?
**A:** The migration script treats all templates except "ƏDV 2% cəlb" as "Tax Free". If you have custom templates with different rates, adjust the script accordingly.
---
## Support
If you encounter issues:
1. Check `IMPLEMENTATION_SUMMARY.md` for implementation details
2. Check logs: `bench --site site1 logs`
3. Review validation errors in the UI
4. Test with a new Purchase Invoice first
---
## Migration Timeline
**Recommended approach:**
1. **Week 1:** Test migration script on staging/development
2. **Week 2:** Migrate draft documents on production
3. **Week 3:** Migrate submitted documents on production
4. **Week 4:** Verify all E-Taxes integrations work correctly
**Note:** No deadline - you can migrate documents as needed. New documents will use the new fields automatically.
---
## Example Migration Session
```bash
# 1. Backup database
bench --site site1 backup
# 2. Run migration
bench --site site1 console
# 3. Paste migration script (see Option 2 above)
# 4. Verify results
# Sample output:
# Found 15 agricultural purchase invoices
# ============================================================
# ✓ Migrated: ACC-PINV-2026-00001 (3 items)
# ✓ Migrated: ACC-PINV-2026-00002 (5 items)
# ⊘ Skipped: ACC-PINV-2026-00003 (no items to migrate)
# ...
# ============================================================
# Migration Complete:
# - Migrated: 12
# - Skipped: 3
# - Total: 15
# 5. Clear cache
bench --site site1 clear-cache
# 6. Test in UI
# Open one of the migrated documents and verify tax_type is set
```
---
## Conclusion
✅ Migration is optional but recommended
✅ Old and new systems coexist
✅ No data loss - both fields are preserved
✅ Easy rollback via database backup
**For new documents:** Just use the new `tax_type` field - no migration needed!