- 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>
501 lines
25 KiB
PHP
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">×</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">×</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">×</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>
|