Files
desk-moloni/modules/desk_moloni/views/admin/mapping_management.php
Emanuel Almeida 8c4f68576f chore: add spec-kit and standardize signatures
- 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>
2025-09-12 01:27:37 +01:00

501 lines
25 KiB
PHP

/**
* Descomplicar® Crescimento Digital
* https://descomplicar.pt
*/
<?php defined('BASEPATH') or exit('No direct script access allowed'); ?>
<div class="row">
<div class="col-md-12">
<div class="panel_s">
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<h4 class="no-margin">
<i class="fa fa-exchange" aria-hidden="true"></i>
<?php echo _l('desk_moloni_mapping_management'); ?>
</h4>
</div>
<div class="col-md-6 text-right">
<div class="btn-group">
<?php if (has_permission('desk_moloni', '', 'create')) { ?>
<button type="button" class="btn btn-success" data-toggle="modal" data-target="#create-mapping-modal">
<i class="fa fa-plus"></i> <?php echo _l('desk_moloni_create_mapping'); ?>
</button>
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#auto-discover-modal">
<i class="fa fa-magic"></i> <?php echo _l('desk_moloni_auto_discover'); ?>
</button>
<?php } ?>
<button type="button" class="btn btn-default" id="refresh-mappings">
<i class="fa fa-refresh"></i> <?php echo _l('refresh'); ?>
</button>
</div>
<a href="<?php echo admin_url('modules/desk_moloni'); ?>" class="btn btn-default ml-2">
<i class="fa fa-arrow-left"></i> <?php echo _l('back_to_dashboard'); ?>
</a>
</div>
</div>
<hr class="hr-panel-separator" />
<!-- Mapping Statistics Cards -->
<div class="row" id="mapping-stats">
<div class="col-lg-3 col-md-6">
<div class="panel panel-info">
<div class="panel-body">
<div class="row">
<div class="col-xs-3">
<i class="fa fa-exchange fa-3x"></i>
</div>
<div class="col-xs-9 text-right">
<div class="huge" id="total-mappings"><?php echo $mapping_stats['total_mappings'] ?? 0; ?></div>
<div><?php echo _l('desk_moloni_total_mappings'); ?></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="panel panel-success">
<div class="panel-body">
<div class="row">
<div class="col-xs-3">
<i class="fa fa-arrows-h fa-3x"></i>
</div>
<div class="col-xs-9 text-right">
<div class="huge" id="bidirectional-mappings"><?php echo $mapping_stats['bidirectional_mappings'] ?? 0; ?></div>
<div><?php echo _l('desk_moloni_bidirectional'); ?></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="panel panel-warning">
<div class="panel-body">
<div class="row">
<div class="col-xs-3">
<i class="fa fa-clock-o fa-3x"></i>
</div>
<div class="col-xs-9 text-right">
<div class="huge" id="recent-syncs"><?php echo $mapping_stats['recent_syncs'] ?? 0; ?></div>
<div><?php echo _l('desk_moloni_synced_today'); ?></div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-3 col-md-6">
<div class="panel panel-danger">
<div class="panel-body">
<div class="row">
<div class="col-xs-3">
<i class="fa fa-exclamation-triangle fa-3x"></i>
</div>
<div class="col-xs-9 text-right">
<div class="huge" id="unmapped-entities"><?php echo $mapping_stats['unmapped_entities'] ?? 0; ?></div>
<div><?php echo _l('desk_moloni_unmapped_entities'); ?></div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Filters and Search -->
<div class="row">
<div class="col-md-12">
<div class="panel_s">
<div class="panel-body">
<form id="mapping-filters">
<div class="row">
<div class="col-md-2">
<select class="form-control" name="entity_type" id="filter-entity-type">
<option value=""><?php echo _l('desk_moloni_all_entities'); ?></option>
<?php foreach ($entity_types as $type) { ?>
<option value="<?php echo $type; ?>"><?php echo _l('desk_moloni_entity_' . $type); ?></option>
<?php } ?>
</select>
</div>
<div class="col-md-2">
<select class="form-control" name="sync_direction" id="filter-sync-direction">
<option value=""><?php echo _l('desk_moloni_all_directions'); ?></option>
<option value="bidirectional"><?php echo _l('desk_moloni_bidirectional'); ?></option>
<option value="perfex_to_moloni"><?php echo _l('desk_moloni_perfex_to_moloni'); ?></option>
<option value="moloni_to_perfex"><?php echo _l('desk_moloni_moloni_to_perfex'); ?></option>
</select>
</div>
<div class="col-md-3">
<input type="text" class="form-control" name="search" id="filter-search" placeholder="<?php echo _l('desk_moloni_search_mappings'); ?>">
</div>
<div class="col-md-2">
<input type="date" class="form-control" name="last_sync_from" id="filter-last-sync-from" placeholder="<?php echo _l('desk_moloni_sync_from'); ?>">
</div>
<div class="col-md-2">
<input type="date" class="form-control" name="last_sync_to" id="filter-last-sync-to" placeholder="<?php echo _l('desk_moloni_sync_to'); ?>">
</div>
<div class="col-md-1">
<button type="button" class="btn btn-primary btn-block" id="apply-mapping-filters">
<i class="fa fa-filter"></i>
</button>
</div>
</div>
<div class="row mt-2">
<div class="col-md-12">
<button type="button" class="btn btn-default btn-sm" id="clear-mapping-filters">
<i class="fa fa-times"></i> <?php echo _l('clear_filters'); ?>
</button>
</div>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Mappings Table -->
<div class="row">
<div class="col-md-12">
<div class="panel_s">
<div class="panel-body">
<div class="row">
<div class="col-md-6">
<div class="checkbox">
<input type="checkbox" id="select-all-mappings">
<label for="select-all-mappings"><?php echo _l('desk_moloni_select_all'); ?></label>
</div>
</div>
<div class="col-md-6 text-right">
<?php if (has_permission('desk_moloni', '', 'edit')) { ?>
<div class="btn-group" id="bulk-mapping-actions" style="display: none;">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-cogs"></i> <?php echo _l('desk_moloni_bulk_actions'); ?> <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#" data-bulk-action="sync_perfex_to_moloni"><?php echo _l('desk_moloni_set_perfex_to_moloni'); ?></a></li>
<li><a href="#" data-bulk-action="sync_moloni_to_perfex"><?php echo _l('desk_moloni_set_moloni_to_perfex'); ?></a></li>
<li><a href="#" data-bulk-action="sync_bidirectional"><?php echo _l('desk_moloni_set_bidirectional'); ?></a></li>
<li role="separator" class="divider"></li>
<li><a href="#" data-bulk-action="delete" class="text-danger"><?php echo _l('desk_moloni_delete_selected'); ?></a></li>
</ul>
</div>
<?php } ?>
</div>
</div>
<div class="table-responsive mt-3">
<table class="table table-hover" id="mappings-table">
<thead>
<tr>
<th width="30px">
<input type="checkbox" id="table-select-all-mappings">
</th>
<th><?php echo _l('desk_moloni_entity_type'); ?></th>
<th><?php echo _l('desk_moloni_perfex_entity'); ?></th>
<th><?php echo _l('desk_moloni_moloni_entity'); ?></th>
<th><?php echo _l('desk_moloni_sync_direction'); ?></th>
<th><?php echo _l('desk_moloni_last_sync'); ?></th>
<th><?php echo _l('desk_moloni_actions'); ?></th>
</tr>
</thead>
<tbody>
<tr>
<td colspan="7" class="text-center">
<i class="fa fa-spinner fa-spin"></i> <?php echo _l('loading'); ?>
</td>
</tr>
</tbody>
</table>
</div>
<!-- Pagination -->
<div class="row">
<div class="col-md-6">
<div id="mapping-pagination-info"></div>
</div>
<div class="col-md-6">
<nav aria-label="Mapping pagination">
<ul class="pagination pull-right" id="mapping-pagination-controls">
</ul>
</nav>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Create Mapping Modal -->
<div class="modal fade" id="create-mapping-modal" tabindex="-1" role="dialog" aria-labelledby="createMappingModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="createMappingModalLabel">
<i class="fa fa-plus"></i> <?php echo _l('desk_moloni_create_entity_mapping'); ?>
</h4>
</div>
<form id="create-mapping-form">
<div class="modal-body">
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="mapping_entity_type"><?php echo _l('desk_moloni_entity_type'); ?></label>
<select class="form-control" name="entity_type" id="mapping_entity_type" required>
<option value=""><?php echo _l('desk_moloni_select_entity_type'); ?></option>
<option value="client"><?php echo _l('desk_moloni_entity_client'); ?></option>
<option value="product"><?php echo _l('desk_moloni_entity_product'); ?></option>
<option value="invoice"><?php echo _l('desk_moloni_entity_invoice'); ?></option>
<option value="estimate"><?php echo _l('desk_moloni_entity_estimate'); ?></option>
<option value="credit_note"><?php echo _l('desk_moloni_entity_credit_note'); ?></option>
</select>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="sync_direction"><?php echo _l('desk_moloni_sync_direction'); ?></label>
<select class="form-control" name="sync_direction" id="sync_direction">
<option value="bidirectional"><?php echo _l('desk_moloni_bidirectional'); ?></option>
<option value="perfex_to_moloni"><?php echo _l('desk_moloni_perfex_to_moloni'); ?></option>
<option value="moloni_to_perfex"><?php echo _l('desk_moloni_moloni_to_perfex'); ?></option>
</select>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group">
<label for="perfex_entity"><?php echo _l('desk_moloni_perfex_entity'); ?></label>
<select class="form-control" name="perfex_id" id="perfex_entity" required>
<option value=""><?php echo _l('desk_moloni_select_perfex_entity'); ?></option>
</select>
<small class="help-block"><?php echo _l('desk_moloni_perfex_entity_help'); ?></small>
</div>
</div>
<div class="col-md-6">
<div class="form-group">
<label for="moloni_entity"><?php echo _l('desk_moloni_moloni_entity'); ?></label>
<select class="form-control" name="moloni_id" id="moloni_entity" required>
<option value=""><?php echo _l('desk_moloni_select_moloni_entity'); ?></option>
</select>
<small class="help-block"><?php echo _l('desk_moloni_moloni_entity_help'); ?></small>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
<?php echo _l('cancel'); ?>
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-plus"></i> <?php echo _l('desk_moloni_create_mapping'); ?>
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Auto-Discover Modal -->
<div class="modal fade" id="auto-discover-modal" tabindex="-1" role="dialog" aria-labelledby="autoDiscoverModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="autoDiscoverModalLabel">
<i class="fa fa-magic"></i> <?php echo _l('desk_moloni_auto_discover_mappings'); ?>
</h4>
</div>
<form id="auto-discover-form">
<div class="modal-body">
<div class="form-group">
<label for="discover_entity_type"><?php echo _l('desk_moloni_entity_type'); ?></label>
<select class="form-control" name="entity_type" id="discover_entity_type" required>
<option value=""><?php echo _l('desk_moloni_select_entity_type'); ?></option>
<option value="client"><?php echo _l('desk_moloni_entity_client'); ?></option>
<option value="product"><?php echo _l('desk_moloni_entity_product'); ?></option>
</select>
<small class="help-block"><?php echo _l('desk_moloni_auto_discover_help'); ?></small>
</div>
<div class="form-group">
<div class="checkbox checkbox-primary">
<input type="checkbox" name="auto_create" id="auto_create" value="1">
<label for="auto_create"><?php echo _l('desk_moloni_auto_create_mappings'); ?></label>
</div>
<small class="help-block"><?php echo _l('desk_moloni_auto_create_help'); ?></small>
</div>
<div id="discovery-preview" style="display: none;">
<h5><?php echo _l('desk_moloni_suggested_mappings'); ?>:</h5>
<div id="discovery-results"></div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
<?php echo _l('cancel'); ?>
</button>
<button type="submit" class="btn btn-info">
<i class="fa fa-magic"></i> <?php echo _l('desk_moloni_discover_mappings'); ?>
</button>
</div>
</form>
</div>
</div>
</div>
<!-- Edit Mapping Modal -->
<div class="modal fade" id="edit-mapping-modal" tabindex="-1" role="dialog" aria-labelledby="editMappingModalLabel" aria-hidden="true">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">&times;</span>
</button>
<h4 class="modal-title" id="editMappingModalLabel">
<i class="fa fa-edit"></i> <?php echo _l('desk_moloni_edit_mapping'); ?>
</h4>
</div>
<form id="edit-mapping-form">
<input type="hidden" name="mapping_id" id="edit_mapping_id">
<div class="modal-body">
<div class="row">
<div class="col-md-12">
<div id="edit-mapping-info"></div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group">
<label for="edit_sync_direction"><?php echo _l('desk_moloni_sync_direction'); ?></label>
<select class="form-control" name="sync_direction" id="edit_sync_direction">
<option value="bidirectional"><?php echo _l('desk_moloni_bidirectional'); ?></option>
<option value="perfex_to_moloni"><?php echo _l('desk_moloni_perfex_to_moloni'); ?></option>
<option value="moloni_to_perfex"><?php echo _l('desk_moloni_moloni_to_perfex'); ?></option>
</select>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
<?php echo _l('cancel'); ?>
</button>
<button type="submit" class="btn btn-primary">
<i class="fa fa-save"></i> <?php echo _l('save_changes'); ?>
</button>
</div>
</form>
</div>
</div>
</div>
<script src="<?php echo module_dir_url('desk_moloni', 'assets/js/mapping_management.js'); ?>"></script>
<style>
.huge {
font-size: 40px;
}
.sync-direction-badge {
font-size: 11px;
padding: 4px 8px;
border-radius: 12px;
}
.sync-direction-bidirectional {
background-color: #5cb85c;
color: white;
}
.sync-direction-perfex-to-moloni {
background-color: #5bc0de;
color: white;
}
.sync-direction-moloni-to-perfex {
background-color: #f0ad4e;
color: white;
}
.entity-info {
display: flex;
align-items: center;
gap: 8px;
}
.entity-info .fa {
width: 16px;
text-align: center;
}
.mapping-actions .btn {
margin-right: 2px;
margin-bottom: 2px;
}
.table th {
background-color: #f8f9fa;
}
#bulk-mapping-actions {
margin-left: 10px;
}
.discovery-item {
padding: 8px;
margin: 4px 0;
border: 1px solid #ddd;
border-radius: 4px;
background-color: #f9f9f9;
}
.discovery-item strong {
color: #333;
}
.discovery-confidence {
float: right;
font-size: 11px;
padding: 2px 6px;
border-radius: 10px;
}
.confidence-high {
background-color: #d73925;
color: white;
}
.confidence-medium {
background-color: #f0ad4e;
color: white;
}
.confidence-low {
background-color: #5cb85c;
color: white;
}
#edit-mapping-info {
background-color: #f8f9fa;
padding: 15px;
border-radius: 5px;
margin-bottom: 20px;
}
#edit-mapping-info .row {
margin-bottom: 10px;
}
#edit-mapping-info .row:last-child {
margin-bottom: 0;
}
</style>