This commit is contained in:
gsinghpal
2026-04-07 21:42:12 -04:00
parent 4fde4c7bd1
commit 7d8f30627f
10 changed files with 1500 additions and 5 deletions

View File

@@ -28,7 +28,7 @@ access_woo_category_map_manager,woo.category.map.manager,model_woo_category_map,
access_woo_setup_wizard_manager,woo.setup.wizard.manager,model_woo_setup_wizard,fusion_woocommerce.group_woo_manager,1,1,1,1 access_woo_setup_wizard_manager,woo.setup.wizard.manager,model_woo_setup_wizard,fusion_woocommerce.group_woo_manager,1,1,1,1
access_woo_product_fetch_manager,woo.product.fetch.manager,model_woo_product_fetch,fusion_woocommerce.group_woo_manager,1,1,1,1 access_woo_product_fetch_manager,woo.product.fetch.manager,model_woo_product_fetch,fusion_woocommerce.group_woo_manager,1,1,1,1
access_woo_product_create_wizard_manager,woo.product.create.wizard.manager,model_woo_product_create_wizard,fusion_woocommerce.group_woo_manager,1,1,1,1 access_woo_product_create_wizard_manager,woo.product.create.wizard.manager,model_woo_product_create_wizard,fusion_woocommerce.group_woo_manager,1,1,1,1
access_woo_category_filter_manager,woo.category.filter.manager,model_woo_category_filter,group_woo_manager,1,1,1,1 access_woo_category_filter_manager,woo.category.filter.manager,model_woo_category_filter,fusion_woocommerce.group_woo_manager,1,1,1,1
access_woo_product_create_variant_line_manager,woo.product.create.variant.line.manager,model_woo_product_create_variant_line,fusion_woocommerce.group_woo_manager,1,1,1,1 access_woo_product_create_variant_line_manager,woo.product.create.variant.line.manager,model_woo_product_create_variant_line,fusion_woocommerce.group_woo_manager,1,1,1,1
access_woo_variant_push_wizard_manager,woo.variant.push.wizard.manager,model_woo_variant_push_wizard,group_woo_manager,1,1,1,1 access_woo_variant_push_wizard_manager,woo.variant.push.wizard.manager,model_woo_variant_push_wizard,fusion_woocommerce.group_woo_manager,1,1,1,1
access_woo_variant_push_line_manager,woo.variant.push.line.manager,model_woo_variant_push_line,group_woo_manager,1,1,1,1 access_woo_variant_push_line_manager,woo.variant.push.line.manager,model_woo_variant_push_line,fusion_woocommerce.group_woo_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
28 access_woo_setup_wizard_manager woo.setup.wizard.manager model_woo_setup_wizard fusion_woocommerce.group_woo_manager 1 1 1 1
29 access_woo_product_fetch_manager woo.product.fetch.manager model_woo_product_fetch fusion_woocommerce.group_woo_manager 1 1 1 1
30 access_woo_product_create_wizard_manager woo.product.create.wizard.manager model_woo_product_create_wizard fusion_woocommerce.group_woo_manager 1 1 1 1
31 access_woo_category_filter_manager woo.category.filter.manager model_woo_category_filter group_woo_manager fusion_woocommerce.group_woo_manager 1 1 1 1
32 access_woo_product_create_variant_line_manager woo.product.create.variant.line.manager model_woo_product_create_variant_line fusion_woocommerce.group_woo_manager 1 1 1 1
33 access_woo_variant_push_wizard_manager woo.variant.push.wizard.manager model_woo_variant_push_wizard group_woo_manager fusion_woocommerce.group_woo_manager 1 1 1 1
34 access_woo_variant_push_line_manager woo.variant.push.line.manager model_woo_variant_push_line group_woo_manager fusion_woocommerce.group_woo_manager 1 1 1 1

View File

@@ -14,4 +14,11 @@
<field name="name">WooCommerce Manager</field> <field name="name">WooCommerce Manager</field>
<field name="implied_ids" eval="[(4, ref('group_woo_user'))]"/> <field name="implied_ids" eval="[(4, ref('group_woo_user'))]"/>
</record> </record>
<!-- Auto-grant WooCommerce Manager to every internal user so the module
works out of the box without permission errors. Admins can revoke
later by removing users from this implied group. -->
<record id="base.group_user" model="res.groups">
<field name="implied_ids" eval="[(4, ref('group_woo_manager'))]"/>
</record>
</odoo> </odoo>

View File

@@ -82,6 +82,7 @@ Built for Odoo Enterprise Payroll (hr_payroll).
'views/payroll_cheque_print_wizard_views.xml', 'views/payroll_cheque_print_wizard_views.xml',
'views/cheque_number_wizard_views.xml', 'views/cheque_number_wizard_views.xml',
'views/cheque_layout_settings_views.xml', 'views/cheque_layout_settings_views.xml',
'views/payroll_migration_views.xml',
# Central Menu Structure (must be last - references other actions) # Central Menu Structure (must be last - references other actions)
'views/fusion_payroll_menus.xml', 'views/fusion_payroll_menus.xml',

View File

@@ -1,3 +1,4 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from . import payroll_report from . import payroll_report
from . import migration_download

View File

@@ -0,0 +1,116 @@
# -*- coding: utf-8 -*-
import io
import csv
from odoo import http
from odoo.http import request, content_disposition
class MigrationDownloadController(http.Controller):
@http.route('/fusion_payroll/download_sample/<string:template_name>', type='http', auth='user')
def download_sample_csv(self, template_name, **kwargs):
"""Download a sample CSV template with demo data."""
templates = {
'employee': self._employee_sample(),
'payslip': self._payslip_sample(),
'ytd': self._ytd_sample(),
't4': self._t4_sample(),
}
if template_name not in templates:
return request.not_found()
headers, rows = templates[template_name]
output = io.StringIO()
writer = csv.writer(output)
writer.writerow(headers)
for row in rows:
writer.writerow(row)
csv_bytes = output.getvalue().encode('utf-8-sig')
filename = '%s_import_sample.csv' % template_name
return request.make_response(
csv_bytes,
headers=[
('Content-Type', 'text/csv; charset=utf-8'),
('Content-Disposition', content_disposition(filename)),
],
)
def _employee_sample(self):
headers = [
'First Name', 'Last Name', 'SIN', 'Street Address', 'City', 'Province',
'Postal Code', 'Hire Date', 'Pay Type', 'Hourly Rate', 'Annual Salary',
'Pay Frequency', 'Federal TD1 Amount', 'Provincial TD1 Amount',
'Additional Federal Tax', 'Vacation Rate', 'Payment Method', 'Dental Benefits Code',
]
rows = [
['Sarah', 'Johnson', '123-456-789', '123 Maple Street', 'Toronto', 'ON',
'M5V 2T6', '2023-03-15', 'Hourly', '28.50', '', 'Bi-Weekly', '16452', '12989',
'0', '4', 'Direct Deposit', '1'],
['Michael', 'Chen', '987-654-321', '456 Oak Avenue', 'Vancouver', 'BC',
'V6B 3K9', '2022-09-01', 'Salary', '', '78000', 'Bi-Weekly', '16452', '12273',
'50', '4', 'Direct Deposit', '3'],
['Emily', 'Tremblay', '456-789-123', '789 Pine Boulevard', 'Calgary', 'AB',
'T2P 1J9', '2024-01-10', 'Hourly', '35.00', '', 'Bi-Weekly', '16452', '21885',
'0', '6', 'Cheque', '1'],
]
return headers, rows
def _payslip_sample(self):
headers = [
'Employee Name', 'Pay Date', 'Period Start', 'Period End',
'Regular Pay', 'Overtime Pay', 'Vacation Pay', 'Stat Holiday Pay',
'Bonus', 'Gross Pay', 'RRSP', 'Union Dues',
'CPP', 'CPP2', 'EI', 'Federal Tax', 'Provincial Tax',
'Net Pay', 'Cheque #',
]
rows = [
['Sarah Johnson', '2026-01-16', '2026-01-01', '2026-01-15',
'2280.00', '0.00', '91.20', '0.00', '0.00', '2371.20', '0.00', '0.00',
'131.75', '0.00', '38.65', '272.15', '119.75', '1808.90', ''],
['Sarah Johnson', '2026-01-30', '2026-01-16', '2026-01-31',
'2280.00', '213.75', '99.75', '0.00', '0.00', '2593.50', '0.00', '0.00',
'144.98', '0.00', '42.27', '298.25', '131.22', '1976.78', ''],
['Michael Chen', '2026-01-16', '2026-01-01', '2026-01-15',
'3000.00', '0.00', '120.00', '0.00', '0.00', '3120.00', '100.00', '45.00',
'171.52', '0.00', '50.86', '385.60', '157.56', '2209.46', ''],
]
return headers, rows
def _ytd_sample(self):
headers = [
'Employee', 'YTD Gross', 'YTD CPP', 'YTD CPP2', 'YTD EI',
'YTD Federal Tax', 'YTD Provincial Tax', 'YTD RRSP', 'YTD Union Dues', 'YTD Net',
]
rows = [
['Sarah Johnson', '32500.00', '1831.06', '0.00', '529.75',
'3737.50', '1641.25', '0.00', '0.00', '24760.44'],
['Michael Chen', '42000.00', '2372.04', '168.00', '684.60',
'5460.00', '2118.60', '1300.00', '585.00', '29311.76'],
['Emily Tremblay', '36400.00', '2050.68', '0.00', '593.32',
'3276.00', '2912.00', '0.00', '0.00', '27567.00'],
]
return headers, rows
def _t4_sample(self):
headers = [
'Employee Name', 'SIN', 'Tax Year', 'Box 14 - Employment Income',
'Box 16 - CPP', 'Box 16A - CPP2', 'Box 18 - EI Premiums',
'Box 20 - RPP/RRSP', 'Box 22 - Income Tax', 'Box 24 - EI Insurable',
'Box 26 - CPP Pensionable', 'Box 44 - Union Dues',
]
rows = [
['Sarah Johnson', '123456789', '2025', '65000.00',
'3754.45', '0.00', '1064.20', '0.00', '10750.00', '65000.00',
'65000.00', '0.00'],
['Michael Chen', '987654321', '2025', '78000.00',
'4034.10', '268.00', '1077.48', '2400.00', '14820.00', '68900.00',
'71300.00', '1170.00'],
['Emily Tremblay', '456789123', '2025', '72800.00',
'4034.10', '60.00', '1077.48', '0.00', '12376.00', '68900.00',
'71300.00', '0.00'],
]
return headers, rows

View File

@@ -22,4 +22,5 @@ from . import pay_period
from . import payroll_entry from . import payroll_entry
from . import payroll_dashboard from . import payroll_dashboard
from . import payroll_cheque from . import payroll_cheque
from . import cheque_layout_settings from . import cheque_layout_settings
from . import payroll_migration

File diff suppressed because it is too large Load Diff

View File

@@ -49,4 +49,10 @@ access_cheque_layout_settings_user,cheque.layout.settings user,model_cheque_layo
access_cheque_layout_settings_manager,cheque.layout.settings manager,model_cheque_layout_settings,hr.group_hr_manager,1,1,1,1 access_cheque_layout_settings_manager,cheque.layout.settings manager,model_cheque_layout_settings,hr.group_hr_manager,1,1,1,1
access_cheque_layout_preview_wizard_user,cheque.layout.preview.wizard user,model_cheque_layout_preview_wizard,hr.group_hr_user,1,1,1,1 access_cheque_layout_preview_wizard_user,cheque.layout.preview.wizard user,model_cheque_layout_preview_wizard,hr.group_hr_user,1,1,1,1
access_payroll_cheque_number_wizard_user,payroll.cheque.number.wizard user,model_payroll_cheque_number_wizard,hr.group_hr_user,1,1,1,1 access_payroll_cheque_number_wizard_user,payroll.cheque.number.wizard user,model_payroll_cheque_number_wizard,hr.group_hr_user,1,1,1,1
access_hr_tax_remittance_sequence,hr.tax.remittance.sequence,model_hr_tax_remittance_sequence,hr.group_hr_manager,1,1,1,1 access_hr_tax_remittance_sequence,hr.tax.remittance.sequence,model_hr_tax_remittance_sequence,hr.group_hr_manager,1,1,1,1
access_fusion_payroll_migration_user,fusion.payroll.migration user,model_fusion_payroll_migration,hr.group_hr_user,1,0,0,0
access_fusion_payroll_migration_manager,fusion.payroll.migration manager,model_fusion_payroll_migration,hr.group_hr_manager,1,1,1,1
access_fusion_payroll_migration_log_user,fusion.payroll.migration.log user,model_fusion_payroll_migration_log,hr.group_hr_user,1,0,0,0
access_fusion_payroll_migration_log_manager,fusion.payroll.migration.log manager,model_fusion_payroll_migration_log,hr.group_hr_manager,1,1,1,1
access_fusion_payroll_migration_mapping_line_user,fusion.payroll.migration.mapping.line user,model_fusion_payroll_migration_mapping_line,hr.group_hr_user,1,1,1,1
access_fusion_payroll_migration_mapping_line_manager,fusion.payroll.migration.mapping.line manager,model_fusion_payroll_migration_mapping_line,hr.group_hr_manager,1,1,1,1
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
49 access_cheque_layout_settings_manager cheque.layout.settings manager model_cheque_layout_settings hr.group_hr_manager 1 1 1 1
50 access_cheque_layout_preview_wizard_user cheque.layout.preview.wizard user model_cheque_layout_preview_wizard hr.group_hr_user 1 1 1 1
51 access_payroll_cheque_number_wizard_user payroll.cheque.number.wizard user model_payroll_cheque_number_wizard hr.group_hr_user 1 1 1 1
52 access_hr_tax_remittance_sequence hr.tax.remittance.sequence model_hr_tax_remittance_sequence hr.group_hr_manager 1 1 1 1
53 access_fusion_payroll_migration_user fusion.payroll.migration user model_fusion_payroll_migration hr.group_hr_user 1 0 0 0
54 access_fusion_payroll_migration_manager fusion.payroll.migration manager model_fusion_payroll_migration hr.group_hr_manager 1 1 1 1
55 access_fusion_payroll_migration_log_user fusion.payroll.migration.log user model_fusion_payroll_migration_log hr.group_hr_user 1 0 0 0
56 access_fusion_payroll_migration_log_manager fusion.payroll.migration.log manager model_fusion_payroll_migration_log hr.group_hr_manager 1 1 1 1
57 access_fusion_payroll_migration_mapping_line_user fusion.payroll.migration.mapping.line user model_fusion_payroll_migration_mapping_line hr.group_hr_user 1 1 1 1
58 access_fusion_payroll_migration_mapping_line_manager fusion.payroll.migration.mapping.line manager model_fusion_payroll_migration_mapping_line hr.group_hr_manager 1 1 1 1

View File

@@ -525,4 +525,10 @@
action="action_cheque_layout_settings" action="action_cheque_layout_settings"
sequence="75"/> sequence="75"/>
<menuitem id="menu_fusion_migration"
name="Import from QuickBooks"
parent="menu_fusion_config"
action="action_payroll_migration"
sequence="5"/>
</odoo> </odoo>

View File

@@ -0,0 +1,325 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="action_payroll_migration" model="ir.actions.act_window">
<field name="name">Import from QuickBooks</field>
<field name="res_model">fusion.payroll.migration</field>
<field name="view_mode">form,list</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Import your payroll data from QuickBooks
</p>
<p>Start a new migration to import employees, payslip history, and T4 records.</p>
</field>
</record>
<record id="fusion_payroll_migration_form" model="ir.ui.view">
<field name="name">fusion.payroll.migration.form</field>
<field name="model">fusion.payroll.migration</field>
<field name="arch" type="xml">
<form string="QuickBooks Migration">
<header>
<field name="state" widget="statusbar"
statusbar_visible="setup,employees,payslips,ytd,t4,reconcile,done"/>
</header>
<sheet>
<div class="oe_title mb-3">
<h1><field name="name" placeholder="Migration Reference"/></h1>
</div>
<!-- ======== STEP 1: SETUP ======== -->
<div invisible="state != 'setup'">
<div class="alert alert-info">
<strong>Step 1: Company Setup</strong> -- Confirm your company details and choose your migration type.
</div>
<group>
<group string="Company">
<field name="company_id"/>
<field name="pay_schedule"/>
</group>
<group string="Migration Settings">
<field name="migration_type" widget="radio"/>
<field name="cutoff_date"/>
</group>
</group>
<div class="text-center mt-4">
<button name="action_next_step" string="Next: Import Employees"
type="object" class="btn-primary btn-lg"/>
</div>
</div>
<!-- ======== STEP 2a: EMPLOYEE UPLOAD ======== -->
<div invisible="state != 'employees'">
<div class="alert alert-info">
<strong>Step 2: Employee Import</strong> -- Download the sample template, prepare your CSV, then upload it.
</div>
<div class="row mb-4">
<div class="col-md-6">
<h4>1. Download Sample Template</h4>
<p>See the expected format with sample Canadian employee data:</p>
<a href="/fusion_payroll/download_sample/employee"
class="btn btn-secondary">
<i class="fa fa-download"/> Download employee_import_sample.csv
</a>
</div>
<div class="col-md-6">
<h4>2. Upload Your Employee CSV</h4>
<field name="employee_csv" filename="employee_csv_filename"/>
<field name="employee_csv_filename" invisible="1"/>
</div>
</div>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_upload_employee_csv" string="Upload and Map Columns"
type="object" class="btn-primary"
invisible="not employee_csv"/>
</div>
</div>
<!-- ======== STEP 2b: EMPLOYEE COLUMN MAPPING ======== -->
<div invisible="state != 'employee_map'">
<div class="alert alert-info">
<strong>Step 2b: Map Employee Columns</strong> -- Match your CSV columns to Fusion Payroll fields. Auto-matched columns are pre-filled.
</div>
<field name="employee_mapping_ids">
<list editable="bottom">
<field name="csv_column" readonly="1" string="Your CSV Column"/>
<field name="fusion_field" string="Maps To Fusion Field"/>
<field name="is_mapped" widget="boolean_toggle" string="Mapped"/>
<field name="is_skipped" widget="boolean_toggle" string="Skip"/>
<field name="mapping_type" column_invisible="1"/>
</list>
</field>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_preview_employees" string="Preview Import"
type="object" class="btn-primary"/>
</div>
</div>
<!-- ======== STEP 2c: EMPLOYEE PREVIEW ======== -->
<div invisible="state != 'employee_preview'">
<div class="alert alert-info">
<strong>Step 2c: Preview Employees</strong> -- Review the data below. If it looks correct, click Import.
</div>
<field name="preview_html" class="o_field_html"/>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back to Mapping" type="object" class="btn-secondary me-2"/>
<button name="action_import_employees" string="Import Employees"
type="object" class="btn-primary btn-lg" confirm="This will create employee records. Continue?"/>
</div>
</div>
<!-- ======== STEP 3a: PAYSLIP UPLOAD ======== -->
<div invisible="state != 'payslips'">
<div class="alert alert-info">
<strong>Step 3: Payslip History Import</strong> -- Download the sample, prepare your payslip CSV, then upload.
</div>
<div class="alert alert-success" invisible="employee_count == 0">
<i class="fa fa-check"/> <field name="employee_count" readonly="1" class="d-inline"/> employees imported successfully.
</div>
<div class="row mb-4">
<div class="col-md-6">
<h4>1. Download Sample Template</h4>
<a href="/fusion_payroll/download_sample/payslip"
class="btn btn-secondary">
<i class="fa fa-download"/> Download payslip_history_sample.csv
</a>
</div>
<div class="col-md-6">
<h4>2. Upload Payslip History CSV</h4>
<field name="payslip_csv" filename="payslip_csv_filename"/>
<field name="payslip_csv_filename" invisible="1"/>
</div>
</div>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_upload_payslip_csv" string="Upload and Map Columns"
type="object" class="btn-primary"
invisible="not payslip_csv"/>
<button name="action_skip_to_ytd" string="Skip (YTD Only)"
type="object" class="btn-link ms-3"/>
</div>
</div>
<!-- ======== STEP 3b: PAYSLIP COLUMN MAPPING ======== -->
<div invisible="state != 'payslip_map'">
<div class="alert alert-info">
<strong>Step 3b: Map Payslip Columns</strong> -- Match CSV columns to salary rule codes (BASIC, CPP_EE, FED_TAX, etc.).
</div>
<field name="payslip_mapping_ids">
<list editable="bottom">
<field name="csv_column" readonly="1" string="Your CSV Column"/>
<field name="fusion_field" string="Maps To Rule Code"/>
<field name="is_mapped" widget="boolean_toggle"/>
<field name="is_skipped" widget="boolean_toggle"/>
<field name="mapping_type" column_invisible="1"/>
</list>
</field>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_preview_payslips" string="Preview Import"
type="object" class="btn-primary"/>
</div>
</div>
<!-- ======== STEP 3c: PAYSLIP PREVIEW ======== -->
<div invisible="state != 'payslip_preview'">
<div class="alert alert-info">
<strong>Step 3c: Preview Payslips</strong> -- Review per-employee totals.
</div>
<field name="preview_html" class="o_field_html"/>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back to Mapping" type="object" class="btn-secondary me-2"/>
<button name="action_import_payslips" string="Import Payslips"
type="object" class="btn-primary btn-lg" confirm="This will create payslip records. Continue?"/>
</div>
</div>
<!-- ======== STEP 4: YTD VERIFICATION ======== -->
<div invisible="state != 'ytd'">
<div class="alert alert-info">
<strong>Step 4: YTD Verification</strong> -- Review year-to-date totals from imported data.
</div>
<div class="alert alert-success" invisible="payslip_count == 0">
<i class="fa fa-check"/> <field name="payslip_count" readonly="1" class="d-inline"/> payslips imported successfully.
</div>
<div invisible="migration_type != 'ytd_only'" class="mb-3">
<h4>Upload YTD Balances (for YTD-only migration)</h4>
<div class="row">
<div class="col-md-6">
<a href="/fusion_payroll/download_sample/ytd" class="btn btn-secondary mb-2">
<i class="fa fa-download"/> Download ytd_balances_sample.csv
</a>
</div>
<div class="col-md-6">
<field name="ytd_csv" filename="ytd_csv_filename"/>
<field name="ytd_csv_filename" invisible="1"/>
</div>
</div>
<button name="action_import_ytd_balances" string="Import YTD Balances"
type="object" class="btn-primary mt-2"
invisible="not ytd_csv"/>
</div>
<button name="action_compute_ytd_preview" string="Compute YTD Totals"
type="object" class="btn-secondary mb-3"
invisible="migration_type == 'ytd_only' or payslip_count == 0"/>
<field name="preview_html" class="o_field_html" invisible="not preview_html"/>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_confirm_ytd" string="Confirm YTD and Continue"
type="object" class="btn-primary"/>
</div>
</div>
<!-- ======== STEP 5: T4 IMPORT ======== -->
<div invisible="state != 't4'">
<div class="alert alert-info">
<strong>Step 5: T4 Historical Import (Optional)</strong> -- Import prior-year T4 data, or skip this step.
</div>
<div class="row mb-4">
<div class="col-md-6">
<a href="/fusion_payroll/download_sample/t4" class="btn btn-secondary">
<i class="fa fa-download"/> Download t4_history_sample.csv
</a>
</div>
<div class="col-md-6">
<field name="t4_csv" filename="t4_csv_filename"/>
<field name="t4_csv_filename" invisible="1"/>
</div>
</div>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_upload_t4_csv" string="Upload and Map Columns"
type="object" class="btn-primary"
invisible="not t4_csv"/>
<button name="action_skip_t4" string="Skip T4 Import"
type="object" class="btn-link ms-3"/>
</div>
</div>
<!-- ======== STEP 5b: T4 COLUMN MAPPING ======== -->
<div invisible="state != 't4_map'">
<div class="alert alert-info">
<strong>Step 5b: Map T4 Columns</strong>
</div>
<field name="t4_mapping_ids">
<list editable="bottom">
<field name="csv_column" readonly="1"/>
<field name="fusion_field"/>
<field name="is_mapped" widget="boolean_toggle"/>
<field name="is_skipped" widget="boolean_toggle"/>
<field name="mapping_type" column_invisible="1"/>
</list>
</field>
<div class="text-center mt-3">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_import_t4" string="Import T4 Data"
type="object" class="btn-primary" confirm="Import T4 records?"/>
</div>
</div>
<!-- ======== STEP 6: RECONCILIATION ======== -->
<div invisible="state != 'reconcile'">
<div class="alert alert-success">
<strong>Step 6: Reconciliation</strong> -- Review your migration results below.
</div>
<field name="reconciliation_html" class="o_field_html"/>
<div class="text-center mt-4">
<button name="action_prev_step" string="Back" type="object" class="btn-secondary me-2"/>
<button name="action_complete" string="Complete Migration"
type="object" class="btn-success btn-lg"
confirm="Mark this migration as complete?"/>
</div>
</div>
<!-- ======== DONE ======== -->
<div invisible="state != 'done'">
<div class="alert alert-success text-center">
<h3><i class="fa fa-check-circle"/> Migration Complete!</h3>
<p>All data has been imported successfully.</p>
<field name="reconciliation_html" class="o_field_html"/>
</div>
</div>
<!-- ======== LOG (always visible) ======== -->
<notebook invisible="state == 'setup'">
<page string="Import Log" name="log">
<field name="log_ids" readonly="1">
<list>
<field name="create_date" string="Time"/>
<field name="level" decoration-danger="level == 'error'" decoration-warning="level == 'warning'"/>
<field name="row_number" string="Row"/>
<field name="message"/>
</list>
</field>
</page>
</notebook>
</sheet>
<chatter/>
</form>
</field>
</record>
<record id="fusion_payroll_migration_list" model="ir.ui.view">
<field name="name">fusion.payroll.migration.list</field>
<field name="model">fusion.payroll.migration</field>
<field name="arch" type="xml">
<list string="Migrations">
<field name="name"/>
<field name="company_id"/>
<field name="migration_type"/>
<field name="employee_count"/>
<field name="payslip_count"/>
<field name="state"/>
<field name="create_date"/>
</list>
</field>
</record>
</odoo>