- Added GitHub spec-kit for development workflow - Standardized file signatures to Descomplicar® format - Updated development configuration 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
268 lines
9.9 KiB
PHP
268 lines
9.9 KiB
PHP
/**
|
|
* Descomplicar® Crescimento Digital
|
|
* https://descomplicar.pt
|
|
*/
|
|
|
|
<?php
|
|
defined('BASEPATH') or exit('No direct script access allowed');
|
|
|
|
/**
|
|
* Customer Data Mapper
|
|
*
|
|
* Handles the transformation of client/customer data between Perfex CRM and Moloni formats.
|
|
*
|
|
* @package DeskMoloni\Libraries\Mappers
|
|
* @version 1.0.0
|
|
* @author Descomplicar®
|
|
*/
|
|
class CustomerMapper
|
|
{
|
|
private $CI;
|
|
|
|
public function __construct()
|
|
{
|
|
$this->CI = &get_instance();
|
|
}
|
|
|
|
/**
|
|
* Transform Perfex client data to Moloni format
|
|
*
|
|
* @param array $perfex_client Perfex client data
|
|
* @return array Moloni client data
|
|
*/
|
|
public function toMoloni($perfex_client)
|
|
{
|
|
// Basic client information with comprehensive field mappings
|
|
$moloni_data = [
|
|
'name' => $perfex_client['company'] ?: trim($perfex_client['firstname'] . ' ' . $perfex_client['lastname']),
|
|
'email' => $perfex_client['email'],
|
|
'phone' => $perfex_client['phonenumber'],
|
|
'website' => $perfex_client['website'],
|
|
'vat' => $perfex_client['vat'],
|
|
'number' => $perfex_client['vat'] ?: $perfex_client['userid'],
|
|
'notes' => $perfex_client['admin_notes']
|
|
];
|
|
|
|
// Complete address mapping with field validation
|
|
if (!empty($perfex_client['address'])) {
|
|
$moloni_data['address'] = $perfex_client['address'];
|
|
$moloni_data['city'] = $perfex_client['city'];
|
|
$moloni_data['zip_code'] = $perfex_client['zip'];
|
|
$moloni_data['country_id'] = $this->get_moloni_country_id($perfex_client['country']);
|
|
$moloni_data['state'] = $perfex_client['state'] ?? '';
|
|
}
|
|
|
|
// Shipping address mapping
|
|
if (!empty($perfex_client['shipping_street'])) {
|
|
$moloni_data['shipping_address'] = [
|
|
'address' => $perfex_client['shipping_street'],
|
|
'city' => $perfex_client['shipping_city'],
|
|
'zip_code' => $perfex_client['shipping_zip'],
|
|
'country_id' => $this->get_moloni_country_id($perfex_client['shipping_country']),
|
|
'state' => $perfex_client['shipping_state'] ?? ''
|
|
];
|
|
}
|
|
|
|
// Contact information mapping
|
|
$moloni_data['contact_info'] = [
|
|
'primary_contact' => trim($perfex_client['firstname'] . ' ' . $perfex_client['lastname']),
|
|
'phone' => $perfex_client['phonenumber'],
|
|
'mobile' => $perfex_client['mobile'] ?? '',
|
|
'fax' => $perfex_client['fax'] ?? '',
|
|
'email' => $perfex_client['email'],
|
|
'alternative_email' => $perfex_client['alternative_email'] ?? ''
|
|
];
|
|
|
|
// Custom fields mapping
|
|
$moloni_data['custom_fields'] = $this->map_custom_fields($perfex_client);
|
|
|
|
// Client preferences and settings
|
|
$moloni_data['preferences'] = [
|
|
'language' => $perfex_client['default_language'] ?? 'pt',
|
|
'currency' => $perfex_client['default_currency'] ?? 'EUR',
|
|
'payment_terms' => $perfex_client['payment_terms'] ?? 30,
|
|
'credit_limit' => $perfex_client['credit_limit'] ?? 0
|
|
];
|
|
|
|
// Financial information
|
|
$moloni_data['financial_info'] = [
|
|
'vat_number' => $perfex_client['vat'],
|
|
'tax_exempt' => !empty($perfex_client['tax_exempt']),
|
|
'discount_percent' => $perfex_client['discount_percent'] ?? 0,
|
|
'billing_cycle' => $perfex_client['billing_cycle'] ?? 'monthly'
|
|
];
|
|
|
|
return array_filter($moloni_data, function($value) {
|
|
return $value !== null && $value !== '';
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Transform Moloni client data to Perfex format
|
|
*
|
|
* @param array $moloni_client Moloni client data
|
|
* @return array Perfex client data
|
|
*/
|
|
public function toPerfex($moloni_client)
|
|
{
|
|
// Parse name into first and last name if it's a person
|
|
$name_parts = explode(' ', $moloni_client['name'], 2);
|
|
$is_company = isset($moloni_client['is_company']) ? $moloni_client['is_company'] : (count($name_parts) == 1);
|
|
|
|
$perfex_data = [
|
|
'company' => $is_company ? $moloni_client['name'] : '',
|
|
'firstname' => !$is_company ? $name_parts[0] : '',
|
|
'lastname' => !$is_company && isset($name_parts[1]) ? $name_parts[1] : '',
|
|
'email' => $moloni_client['email'] ?? '',
|
|
'phonenumber' => $moloni_client['phone'] ?? '',
|
|
'website' => $moloni_client['website'] ?? '',
|
|
'vat' => $moloni_client['vat'] ?? '',
|
|
'admin_notes' => $moloni_client['notes'] ?? ''
|
|
];
|
|
|
|
// Address mapping from Moloni to Perfex
|
|
if (!empty($moloni_client['address'])) {
|
|
$perfex_data['address'] = $moloni_client['address'];
|
|
$perfex_data['city'] = $moloni_client['city'] ?? '';
|
|
$perfex_data['zip'] = $moloni_client['zip_code'] ?? '';
|
|
$perfex_data['state'] = $moloni_client['state'] ?? '';
|
|
$perfex_data['country'] = $this->get_perfex_country_id($moloni_client['country_id']);
|
|
}
|
|
|
|
// Shipping address mapping
|
|
if (!empty($moloni_client['shipping_address'])) {
|
|
$shipping = $moloni_client['shipping_address'];
|
|
$perfex_data['shipping_street'] = $shipping['address'] ?? '';
|
|
$perfex_data['shipping_city'] = $shipping['city'] ?? '';
|
|
$perfex_data['shipping_zip'] = $shipping['zip_code'] ?? '';
|
|
$perfex_data['shipping_state'] = $shipping['state'] ?? '';
|
|
$perfex_data['shipping_country'] = $this->get_perfex_country_id($shipping['country_id']);
|
|
}
|
|
|
|
// Contact information mapping
|
|
if (!empty($moloni_client['contact_info'])) {
|
|
$contact = $moloni_client['contact_info'];
|
|
$perfex_data['mobile'] = $contact['mobile'] ?? '';
|
|
$perfex_data['fax'] = $contact['fax'] ?? '';
|
|
$perfex_data['alternative_email'] = $contact['alternative_email'] ?? '';
|
|
}
|
|
|
|
// Preferences mapping
|
|
if (!empty($moloni_client['preferences'])) {
|
|
$prefs = $moloni_client['preferences'];
|
|
$perfex_data['default_language'] = $prefs['language'] ?? 'portuguese';
|
|
$perfex_data['default_currency'] = $prefs['currency'] ?? 'EUR';
|
|
$perfex_data['payment_terms'] = $prefs['payment_terms'] ?? 30;
|
|
$perfex_data['credit_limit'] = $prefs['credit_limit'] ?? 0;
|
|
}
|
|
|
|
// Financial information mapping
|
|
if (!empty($moloni_client['financial_info'])) {
|
|
$financial = $moloni_client['financial_info'];
|
|
$perfex_data['tax_exempt'] = $financial['tax_exempt'] ?? false;
|
|
$perfex_data['discount_percent'] = $financial['discount_percent'] ?? 0;
|
|
$perfex_data['billing_cycle'] = $financial['billing_cycle'] ?? 'monthly';
|
|
}
|
|
|
|
// Map custom fields back to Perfex
|
|
if (!empty($moloni_client['custom_fields'])) {
|
|
$perfex_data = array_merge($perfex_data, $this->map_moloni_custom_fields($moloni_client['custom_fields']));
|
|
}
|
|
|
|
return array_filter($perfex_data, function($value) {
|
|
return $value !== null && $value !== '';
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Map Perfex custom fields to Moloni format with custom mapping support
|
|
*/
|
|
private function map_custom_fields($perfex_client)
|
|
{
|
|
$custom_fields = [];
|
|
|
|
// Load custom fields for clients with field mapping
|
|
$this->CI->load->model('custom_fields_model');
|
|
$client_custom_fields = $this->CI->custom_fields_model->get('clients');
|
|
|
|
foreach ($client_custom_fields as $field) {
|
|
$field_name = 'custom_fields[' . $field['id'] . ']';
|
|
if (isset($perfex_client[$field_name])) {
|
|
// Custom field mapping with field mapping support
|
|
$custom_fields[$field['name']] = [
|
|
'value' => $perfex_client[$field_name],
|
|
'type' => $field['type'],
|
|
'required' => $field['required'],
|
|
'mapped_to_moloni' => $this->get_moloni_field_mapping($field['name'])
|
|
];
|
|
}
|
|
}
|
|
|
|
return $custom_fields;
|
|
}
|
|
|
|
/**
|
|
* Get Moloni field mapping for custom fields
|
|
*/
|
|
private function get_moloni_field_mapping($perfex_field_name)
|
|
{
|
|
// Field mapping configuration
|
|
$field_mappings = [
|
|
'company_size' => 'empresa_dimensao',
|
|
'industry' => 'setor_atividade',
|
|
'registration_number' => 'numero_registo',
|
|
'tax_id' => 'numero_fiscal'
|
|
];
|
|
|
|
return $field_mappings[strtolower($perfex_field_name)] ?? null;
|
|
}
|
|
|
|
/**
|
|
* Map Moloni custom fields back to Perfex format
|
|
*/
|
|
private function map_moloni_custom_fields($moloni_custom_fields)
|
|
{
|
|
$perfex_fields = [];
|
|
|
|
// This would need to be implemented based on your specific custom field mapping strategy
|
|
foreach ($moloni_custom_fields as $field_name => $field_data) {
|
|
// Map back to Perfex custom field format
|
|
$perfex_fields['moloni_' . $field_name] = $field_data['value'];
|
|
}
|
|
|
|
return $perfex_fields;
|
|
}
|
|
|
|
/**
|
|
* Get Moloni country ID from country name/code
|
|
*/
|
|
private function get_moloni_country_id($country)
|
|
{
|
|
if (empty($country)) {
|
|
return null;
|
|
}
|
|
|
|
$country_mappings = [
|
|
'Portugal' => 1, 'PT' => 1,
|
|
'Spain' => 2, 'ES' => 2,
|
|
'France' => 3, 'FR' => 3
|
|
];
|
|
|
|
return $country_mappings[$country] ?? 1; // Default to Portugal
|
|
}
|
|
|
|
/**
|
|
* Get Perfex country ID from Moloni country ID
|
|
*/
|
|
private function get_perfex_country_id($moloni_country_id)
|
|
{
|
|
$country_mappings = [
|
|
1 => 'PT', // Portugal
|
|
2 => 'ES', // Spain
|
|
3 => 'FR' // France
|
|
];
|
|
|
|
return $country_mappings[$moloni_country_id] ?? 'PT';
|
|
}
|
|
}
|