Merge branch 'master' into num-item

This commit is contained in:
Thomas Zilio 2019-02-26 21:38:26 +01:00
commit 0ee271f988
168 changed files with 7489 additions and 5787 deletions

View File

@ -79,18 +79,18 @@ Cerchiamo di essere disponibili quanto possibile, ma non sempre riusciamo a risp
Il progetto presenta, a partire dalla versione 2.4.2, un insieme di test per facilitare il controllo sul corretto funzionamento del gestionale.
Per eseguire i test è necessario seguire le seguenti istruzioni (https://codeception.com/docs/modules/WebDriver):
- Scaricare (Selenium Server)[https://docs.seleniumhq.org/download/] e salvarlo come `selenium-server-standalone.jar` nella cartella principale
- Scaricare (ChromeDriver)[https://sites.google.com/a/chromium.org/chromedriver/getting-started], rendendolo eseguibile da riga di comando (su Windows, aggiungerlo al PATH)
- Configurare localmente Codeception nel file `codeception.yml` con l'URL del web server locale
E' innanzitutto necessario configurare correttamente l'ambiente locale per l'esecuzione dei test:
- Impostare l'URL del web server locale nel file `codeception.yml` per Codeception
```yml
modules:
config:
WebDriver:
url: http://localhost/openstamanager
```
- Eseguire su shell differenti i seguenti comandi:
- Scaricare (ChromeDriver)[https://sites.google.com/a/chromium.org/chromedriver/getting-started], rendendolo eseguibile da riga di comando (su Windows, aggiungerlo al PATH)
E' quindi possibile eseguire i tests avviando dapprima il server ChromeDriver e poi Codeception in shell differenti:
```bash
npm run tests-server # Avvia i server per i test di funzionamento grafico
npm run tests-OSM # Avvia i test
chromedriver --url-base=/wd/hub
php codecept.phar run --steps
```

View File

@ -4,54 +4,76 @@ Tutti i maggiori cambiamenti di questo progetto saranno documentati in questo fi
Il formato utilizzato è basato sulle linee guida di [Keep a Changelog](http://keepachangelog.com/), e il progetto segue il [Semantic Versioning](http://semver.org/) per definire le versioni delle release.
- [2.4.6 (2019-02-12)](#246-2019-02-12)
- [2.4.7 (2019-02-21)](#247-2019-02-21)
- [Aggiunto (Added)](#aggiunto-added)
- [Modificato (Changed)](#modificato-changed)
- [Fixed](#fixed)
- [2.4.5 (2019-01-10)](#245-2019-01-10)
- [2.4.6 (2019-02-12)](#246-2019-02-12)
- [Aggiunto (Added)](#aggiunto-added-1)
- [Modificato (Changed)](#modificato-changed-1)
- [Fixed](#fixed-1)
- [2.4.4 (2018-12-12)](#244-2018-12-12)
- [2.4.5 (2019-01-10)](#245-2019-01-10)
- [Aggiunto (Added)](#aggiunto-added-2)
- [Modificato (Changed)](#modificato-changed-2)
- [Fixed](#fixed-2)
- [2.4.3 (2018-12-07)](#243-2018-12-07)
- [2.4.4 (2018-12-12)](#244-2018-12-12)
- [Aggiunto (Added)](#aggiunto-added-3)
- [Fixed](#fixed-3)
- [2.4.2 (2018-11-14)](#242-2018-11-14)
- [2.4.3 (2018-12-07)](#243-2018-12-07)
- [Aggiunto (Added)](#aggiunto-added-4)
- [Modificato (Changed)](#modificato-changed-2)
- [Fixed](#fixed-4)
- [2.4.2 (2018-11-14)](#242-2018-11-14)
- [Aggiunto (Added)](#aggiunto-added-5)
- [Modificato (Changed)](#modificato-changed-3)
- [Deprecato (Deprecated)](#deprecato-deprecated)
- [Rimosso (Removed)](#rimosso-removed)
- [Sicurezza (Security)](#sicurezza-security)
- [2.4.1 (2018-08-01)](#241-2018-08-01)
- [Aggiunto (Added)](#aggiunto-added-5)
- [Modificato (Changed)](#modificato-changed-3)
- [Fixed](#fixed-4)
- [2.4 (2018-03-30)](#24-2018-03-30)
- [Aggiunto (Added)](#aggiunto-added-6)
- [Modificato (Changed)](#modificato-changed-4)
- [Fixed](#fixed-5)
- [2.3.1 (2018-02-19)](#231-2018-02-19)
- [2.4 (2018-03-30)](#24-2018-03-30)
- [Aggiunto (Added)](#aggiunto-added-7)
- [Modificato (Changed)](#modificato-changed-5)
- [Fixed](#fixed-6)
- [2.3 (2018-02-16)](#23-2018-02-16)
- [2.3.1 (2018-02-19)](#231-2018-02-19)
- [Aggiunto (Added)](#aggiunto-added-8)
- [Modificato (Changed)](#modificato-changed-6)
- [Fixed](#fixed-7)
- [2.3 (2018-02-16)](#23-2018-02-16)
- [Aggiunto (Added)](#aggiunto-added-9)
- [Modificato (Changed)](#modificato-changed-7)
- [Deprecato (Deprecated)](#deprecato-deprecated-1)
- [Rimosso (Removed)](#rimosso-removed-1)
- [Fixed](#fixed-7)
- [Fixed](#fixed-8)
- [Sicurezza (Security)](#sicurezza-security-1)
- [2.2 (2016-11-10)](#22-2016-11-10)
- [Aggiunto (Added)](#aggiunto-added-9)
- [Fixed](#fixed-8)
- [2.1 (2015-04-02)](#21-2015-04-02)
- [Aggiunto (Added)](#aggiunto-added-10)
- [Modificato (Changed)](#modificato-changed-7)
- [Fixed](#fixed-9)
- [2.1 (2015-04-02)](#21-2015-04-02)
- [Aggiunto (Added)](#aggiunto-added-11)
- [Modificato (Changed)](#modificato-changed-8)
- [Fixed](#fixed-10)
## 2.4.7 (2019-02-21)
### Aggiunto (Added)
- Aggiunto possibilità per evitare i movimenti causati da Fatture Elettroniche importate
- Supporto delle fatture alle ritenute contributi
- Solleciti di pagamento nel modulo **Scadenzario**
### Modificato (Changed)
- Miglioramento del sistema di importazione dei diversi documenti in fattura
### Fixed
- Fix di diversi bug nella procedura di importazione XML
- Fix degli sconti nelle note di credito
- Risolti alcuni bug distribuiti
## 2.4.6 (2019-02-12)
### Aggiunto (Added)

View File

@ -156,12 +156,9 @@ if ($structure->permission == 'rw') {
// Operazioni generiche per i campi personalizzati
if (post('op') != null) {
$query = 'SELECT `id`, `name` FROM `zz_fields` WHERE ';
if (!empty($id_plugin)) {
$query .= '`id_plugin` = '.prepare($id_plugin);
} else {
$query .= '`id_module` = '.prepare($id_module);
}
$custom_where = !empty($id_plugin) ? '`id_plugin` = '.prepare($id_plugin) : '`id_module` = '.prepare($id_module);
$query = 'SELECT `id`, `html_name` AS `name` FROM `zz_fields` WHERE '.$custom_where;
$customs = $dbo->fetchArray($query);
if (!starts_with(post('op'), 'delete')) {
@ -188,13 +185,25 @@ if ($structure->permission == 'rw') {
// Aggiornamento
elseif (starts_with(post('op'), 'update')) {
$query = 'SELECT `zz_field_record`.`id_field` FROM `zz_field_record` JOIN `zz_fields` ON `zz_fields`.`id` = `zz_field_record`.`id_field` WHERE id_record = '.prepare($id_record).' AND '.$custom_where;
$customs_present = $dbo->fetchArray($query);
$customs_present = array_column($customs_present, 'id_field');
foreach ($values as $key => $value) {
$dbo->update('zz_field_record', [
'value' => $value,
], [
'id_record' => $id_record,
'id_field' => $key,
]);
if (in_array($key, $customs_present)) {
$dbo->update('zz_field_record', [
'value' => $value,
], [
'id_record' => $id_record,
'id_field' => $key,
]);
} else {
$dbo->insert('zz_field_record', [
'id_record' => $id_record,
'id_field' => $key,
'value' => $value,
]);
}
}
}
}

View File

@ -2,131 +2,82 @@
include_once __DIR__.'/core.php';
use Util\Query;
// Informazioni fondamentali
$start = filter('start');
$length = filter('length');
$columns = filter('columns');
$order = filter('order')[0];
$order['column'] = $order['column'] - 1;
array_shift($columns);
$total = App::readQuery($structure);
$total = Util\Query::readQuery($structure);
// Lettura parametri modulo
$result_query = $total['query'];
// Predisposizione dela risposta
$results = [];
$results['data'] = [];
$results['recordsTotal'] = 0;
$results['recordsFiltered'] = 0;
$results['summable'] = [];
if (!empty($result_query) && $result_query != 'menu' && $result_query != 'custom') {
// Conteggio totale
$results['recordsTotal'] = $dbo->fetchNum($result_query);
// Filtri di ricerica
$search_filters = [];
for ($i = 0; $i < count($columns); ++$i) {
if (!empty($columns[$i]['search']['value'])) {
if (str_contains($total['search_inside'][$i], '|search|')) {
$pieces = explode(',', $columns[$i]['search']['value']);
foreach ($pieces as $piece) {
$piece = trim($piece);
$search_filters[] = str_replace('|search|', prepare('%'.$piece.'%'), $total['search_inside'][$i]);
}
} else {
// Per le icone cerco nel campo icon_title
if (preg_match('/^icon_(.+?)$/', $total['fields'][$i], $m)) {
$total['search_inside'][$i] = '`icon_title_'.$m[1].'`';
}
// Per i colori cerco nel campo color_title
elseif (preg_match('/^color_(.+?)$/', $total['fields'][$i], $m)) {
$total['search_inside'][$i] = '`color_title_'.$m[1].'`';
}
$search_filters[] = $total['search_inside'][$i].' LIKE '.prepare('%'.trim($columns[$i]['search']['value'].'%'));
}
}
// Ricerca
$search = [];
for ($i = 0; $i < count($columns); ++$i) {
if (!empty($columns[$i]['search']['value'])) {
$search[$total['fields'][$i]] = $columns[$i]['search']['value'];
}
}
// Ricerca
if (!empty($search_filters)) {
$result_query = str_replace('2=2', '2=2 AND ('.implode(' AND ', $search_filters).') ', $result_query);
}
$limit = [
'start' => filter('start'),
'length' => filter('length'),
];
// Predisposizione della risposta
$results = [
'data' => [],
'recordsTotal' => 0,
'recordsFiltered' => 0,
'summable' => [],
];
$query = Query::getQuery($structure);
if (!empty($query)) {
// CONTEGGIO TOTALE
$results['recordsTotal'] = $dbo->fetchNum($query);
// RISULTATI VISIBILI
$query = Query::getQuery($structure, $search, $order, $limit);
// Filtri derivanti dai permessi (eventuali)
if (empty($id_plugin)) {
$result_query = Modules::replaceAdditionals($id_module, $result_query);
$query = Modules::replaceAdditionals($id_module, $query);
}
// Ordinamento dei risultati
if (isset($order['dir']) && isset($order['column'])) {
$pieces = explode('ORDER', $result_query);
$count = count($pieces);
if ($count > 1) {
unset($pieces[$count - 1]);
}
$result_query = implode('ORDER', $pieces).' ORDER BY '.$total['order_by'][$order['column']].' '.$order['dir'];
}
// Calcolo di eventuali somme
if (!empty($total['summable'])) {
$sum_query = str_replace_once('SELECT', 'SELECT '.implode(', ', $total['summable']).' FROM(SELECT ', $result_query).') AS `z`';
$sums = $dbo->fetchArray($sum_query)[0];
if (!empty($sums)) {
$r = [];
foreach ($sums as $key => $sum) {
if (str_contains($key, 'sum_')) {
$r[str_replace('sum_', '', $key)] = Translator::numberToLocale($sum);
}
}
$results['summable'] = $r;
}
}
// Paginazione
if ($length > 0) {
$result_query .= ' LIMIT '.$start.', '.$length;
}
// Query effettiva
$query = str_replace_once('SELECT', 'SELECT SQL_CALC_FOUND_ROWS', $result_query);
$rs = $dbo->fetchArray($query);
// Conteggio dei record filtrati
$count = $dbo->fetchArray('SELECT FOUND_ROWS()');
if (!empty($count)) {
$results['recordsFiltered'] = $count[0]['FOUND_ROWS()'];
$data = Query::executeAndCount($query);
$rows = $data['results'];
$results['recordsFiltered'] = $data['count'];
// SOMME
$results['summable'] = Util\Query::getSums($structure, $search);
// Allineamento delle righe
$align = [];
$row = $rows[0] ?: [];
foreach ($row as $field => $value) {
$value = trim($value);
// Allineamento a destra se il valore della prima riga risulta numerica
if (formatter()->isStandardNumber($value)) {
$align[$field] = 'text-right';
}
// Allineamento al centro se il valore della prima riga risulta relativo a date o icone
elseif (formatter()->isStandardDate($value) || preg_match('/^icon_(.+?)$/', $field)) {
$align[$field] = 'text-center';
}
}
// Creazione della tabella
$align = [];
foreach ($rs as $i => $r) {
if ($i == 0) {
foreach ($total['fields'] as $field) {
$value = trim($r[$field]);
foreach ($rows as $i => $r) {
$result = [
'<span class="hide" data-id="'.$r['id'].'"></span>', // Colonna ID
];
// Allineamento a destra se il valore della prima riga risulta numerica
if (formatter()->isStandardNumber($value)) {
$align[$field] = 'text-right';
}
// Allineamento al centro se il valore della prima riga risulta relativo a date o icone
elseif (formatter()->isStandardDate($value) || preg_match('/^icon_(.+?)$/', $field)) {
$align[$field] = 'text-center';
}
}
}
$result = [];
$result[] = '<span class="hide" data-id="'.$r['id'].'"></span>';
foreach ($total['fields'] as $pos => $field) {
$column = [];
@ -219,5 +170,5 @@ if (!empty($result_query) && $result_query != 'menu' && $result_query != 'custom
}
}
$rows = json_encode($results);
echo $rows;
$json = json_encode($results);
echo $json;

View File

@ -4,14 +4,16 @@ include_once __DIR__.'/core.php';
if (!isset($resource)) {
$op = empty($op) ? filter('op') : $op;
$search = filter('q');
$search = filter('search');
$page = filter('page') ?: 0;
$length = filter('length') ?: 100;
if (!isset($elements)) {
$elements = [];
}
$elements = (!is_array($elements)) ? explode(',', $elements) : $elements;
$results = AJAX::select($op, $elements, $search);
$results = AJAX::select($op, $elements, $search, $page, $length);
echo json_encode($results);
}

File diff suppressed because it is too large Load Diff

View File

@ -11,3 +11,4 @@ actor_suffix: Tester
extensions:
enabled:
- Codeception\Extension\RunFailed
#- Codeception\Extension\Recorder

View File

@ -60,7 +60,7 @@
"symfony/var-dumper": "^3.3"
},
"require-dev": {
"codeception/codeception": "2.4.*",
"codeception/codeception": "^2.4",
"friendsofphp/php-cs-fixer": "^2.10",
"phpmd/phpmd": "2.6.0"
},

View File

@ -5,6 +5,7 @@ return [
'modules/anagrafiche' => 'Modules\Anagrafiche',
'modules/articoli' => 'Modules\Articoli',
'modules/ritenute' => 'Modules\Ritenute',
'modules/ritenute_contributi' => 'Modules\RitenuteContributi',
'modules/rivalse' => 'Modules\Rivalse',
'modules/iva' => 'Modules\Iva',
'modules/ddt' => 'Modules\DDT',

View File

@ -87,6 +87,17 @@ if (!API::isAPIRequest()) {
}
$whoops->register();
// Aggiunta di Monolog a Whoops
$whoops->pushHandler(function ($exception, $inspector, $run) use ($logger) {
$logger->addError($exception->getMessage(), [
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTraceAsString(),
]);
});
} else {
$handlers[] = new StreamHandler($docroot.'/logs/api.log', Monolog\Logger::ERROR);
}
@ -109,19 +120,6 @@ foreach ($handlers as $handler) {
// Imposta Monolog come gestore degli errori
Monolog\ErrorHandler::register($logger, [], Monolog\Logger::ERROR, Monolog\Logger::ERROR);
// Aggiunta di Monolog a Whoops
if (App::debug()) {
$whoops->pushHandler(function ($exception, $inspector, $run) use ($logger) {
$logger->addError($exception->getMessage(), [
'code' => $exception->getCode(),
'message' => $exception->getMessage(),
'file' => $exception->getFile(),
'line' => $exception->getLine(),
'trace' => $exception->getTraceAsString(),
]);
});
}
// Database
$dbo = $database = database();

View File

@ -12,33 +12,20 @@ if (empty($id_record) && !empty($id_module)) {
include_once App::filepath('include|custom|', 'top.php');
// Inclusione gli elementi fondamentali
include_once $docroot.'/actions.php';
Util\Query::setSegments(false);
$query = Util\Query::getQuery($module, [
'id' => $id_record,
]);
Util\Query::setSegments(true);
// Widget in alto
echo '{( "name": "widgets", "id_module": "'.$id_module.'", "id_record": "'.$id_record.'", "position": "top", "place": "editor" )}';
$has_access = !empty($query) ? $dbo->fetchNum($query) !== 0 : true;
$advanced_sessions = setting('Attiva notifica di presenza utenti sul record');
if (!empty($advanced_sessions)) {
$dbo->query('DELETE FROM zz_semaphores WHERE id_utente='.prepare(Auth::user()['id']).' AND posizione='.prepare($id_module.', '.$id_record));
$dbo->query('INSERT INTO zz_semaphores (id_utente, posizione, updated) VALUES ('.prepare(Auth::user()['id']).', '.prepare($id_module.', '.$id_record).', NOW())');
echo '
<div class="box box-warning box-solid text-center info-active hide">
<div class="box-header with-border">
<h3 class="box-title"><i class="fa fa-warning"></i> '.tr('Attenzione!').'</h3>
</div>
<div class="box-body">
<p>'.tr('I seguenti utenti stanno visualizzando questa pagina').':</p>
<ul class="list">
</ul>
<p>'.tr('Prestare attenzione prima di effettuare modifiche, poichè queste potrebbero essere perse a causa di multipli salvataggi contemporanei').'.</p>
</div>
</div>';
if ($has_access) {
// Inclusione gli elementi fondamentali
include_once $docroot.'/actions.php';
}
if (empty($record)) {
if (empty($record) || !$has_access) {
echo '
<div class="text-center">
<h3 class="text-muted">'.
@ -53,6 +40,29 @@ if (empty($record)) {
</a>
</div>';
} else {
// Widget in alto
echo '{( "name": "widgets", "id_module": "'.$id_module.'", "id_record": "'.$id_record.'", "position": "top", "place": "editor" )}';
$advanced_sessions = setting('Attiva notifica di presenza utenti sul record');
if (!empty($advanced_sessions)) {
$dbo->query('DELETE FROM zz_semaphores WHERE id_utente='.prepare(Auth::user()['id']).' AND posizione='.prepare($id_module.', '.$id_record));
$dbo->query('INSERT INTO zz_semaphores (id_utente, posizione, updated) VALUES ('.prepare(Auth::user()['id']).', '.prepare($id_module.', '.$id_record).', NOW())');
echo '
<div class="box box-warning box-solid text-center info-active hide">
<div class="box-header with-border">
<h3 class="box-title"><i class="fa fa-warning"></i> '.tr('Attenzione!').'</h3>
</div>
<div class="box-body">
<p>'.tr('I seguenti utenti stanno visualizzando questa pagina').':</p>
<ul class="list">
</ul>
<p>'.tr('Prestare attenzione prima di effettuare modifiche, poichè queste potrebbero essere perse a causa di multipli salvataggi contemporanei').'.</p>
</div>
</div>';
}
echo '
<div class="nav-tabs-custom">
<ul class="nav nav-tabs pull-right" id="tabs" role="tablist">
@ -382,7 +392,6 @@ if ($read_only || !empty($block_edit)) {
};
window.addEventListener("unload", function(e) {
//console.log(e);
$("#main_loading").show();
});

View File

@ -47,7 +47,7 @@ if ($show_rivalsa == 1 || $show_ritenuta_acconto == 1) {
if ($show_rivalsa == 1) {
echo '
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Rivalsa').'", "name": "id_rivalsa_inps", "value": "'.$id_rivalsa_inps.'", "values": "query=SELECT * FROM co_rivalse", "help": "'.(($options['dir'] == 'entrata') ? setting("Tipo Cassa") : null).'" ]}
{[ "type": "select", "label": "'.tr('Rivalsa').'", "name": "id_rivalsa_inps", "value": "'.$id_rivalsa_inps.'", "values": "query=SELECT * FROM co_rivalse", "help": "'.(($options['dir'] == 'entrata') ? setting('Tipo Cassa') : null).'" ]}
</div>';
}
@ -71,12 +71,28 @@ if ($show_rivalsa == 1 || $show_ritenuta_acconto == 1) {
</div>';
}
// Conto
if (empty($options['hide_conto'])) {
if (!empty($options['show-ritenuta-contributi']) || empty($options['hide_conto'])) {
$width = !empty($options['show-ritenuta-contributi']) && empty($options['hide_conto']) ? 6 : 12;
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$result['idconto'].'", "ajax-source": "'.$options['conti'].'" ]}
</div>
<div class="row">';
// Ritenuta contributi
if (!empty($options['show-ritenuta-contributi'])) {
echo '
<div class="col-md-'.$width.'">
{[ "type": "checkbox", "label": "'.tr('Ritenuta contributi').'", "name": "ritenuta_contributi", "value": "'.$result['ritenuta_contributi'].'" ]}
</div>';
}
// Conto
if (empty($options['hide_conto'])) {
echo '
<div class="col-md-'.$width.'">
{[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$result['idconto'].'", "ajax-source": "'.$options['conti'].'" ]}
</div>';
}
echo '
</div>';
}

View File

@ -2,9 +2,7 @@
$result['id'] = isset($result['id']) ? $result['id'] : null;
/*
Form di inserimento riga documento
*/
// Form di inserimento riga documento
echo '
<form action="'.ROOTDIR.'/editor.php?id_module='.$id_module.'&id_record='.$id_record.'" method="post">
<input type="hidden" name="id_plugin" value="'.$id_plugin.'">

309
include/common/importa.php Normal file
View File

@ -0,0 +1,309 @@
<?php
$id_record = $result['id_record'];
$id_documento_finale = $result['id_documento'];
$final_module = Modules::get($options['final_module']);
$original_module = Modules::get($options['original_module']);
$dir = $options['dir'];
$op = $options['op'];
$table = $options['sql']['table'];
$rows = $options['sql']['rows'];
$id_rows = $options['sql']['id_rows'];
// Info documento
$documento = $dbo->fetchOne('SELECT * FROM '.$table.' WHERE id = '.prepare($id_record));
$numero = !empty($documento['numero_esterno']) ? $documento['numero_esterno'] : $documento['numero'];
$id_anagrafica = $documento['idanagrafica'];
$id_pagamento = $documento['idpagamento'];
$id_conto = $documento['idconto'];
if (empty($documento)) {
return;
}
$id_iva = $id_iva ?: setting('Iva predefinita');
if (empty($id_conto)) {
$id_conto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto');
}
// Selezione articoli dell'ordine da portare nel ddt
$righe = $dbo->fetchArray('SELECT *, IFNULL((SELECT codice FROM mg_articoli WHERE id=idarticolo),"") AS codice, (qta - qta_evasa) AS qta_rimanente FROM '.$table.' INNER JOIN '.$rows.' ON '.$table.'.id='.$rows.'.'.$id_rows.' WHERE '.$table.'.id='.prepare($id_record).' HAVING qta_rimanente > 0 OR is_descrizione = 1 ORDER BY `order`');
if (!empty($righe)) {
echo '
<form action="'.ROOTDIR.'/controller.php?id_module='.$final_module['id'].(!empty($id_documento_finale) ? '&id_record='.$id_documento_finale : '').'" method="post">
<input type="hidden" name="'.$options['id_importazione'].'" value="'.$id_record.'">
<input type="hidden" name="idanagrafica" value="'.$id_anagrafica.'">
<input type="hidden" name="idconto" value="'.$id_conto.'">
<input type="hidden" name="idpagamento" value="'.$id_pagamento.'">
<input type="hidden" name="iddocumento" value="'.$id_record.'">
<input type="hidden" name="op" value="'.$op.'">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="dir" value="'.$dir.'">';
// Creazione fattura dal documento
if (!empty($options['create_document'])) {
echo '
<div class="row">
<input type="hidden" name="create_document" value="on"/>
<div class="col-md-6">
{[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]}
</div>';
if ($final_module['name'] == 'Fatture di vendita' || $final_module['name'] == 'Fatture di acquisto') {
if ($op == 'nota_accredito' && !empty($segmenti)) {
$segmento = $dbo->fetchOne("SELECT * FROM zz_segments WHERE predefined_accredito='1'");
$id_segment = $segmento['id'];
} else {
$id_segment = $_SESSION['module_'.$final_module['id']]['id_segment'];
}
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare($final_module['id']).' ORDER BY name", "value": "'.$id_segment.'" ]}
</div>';
}
echo '
</div>';
}
// Conto
if (($final_module['name'] == 'Fatture di vendita' || $final_module['name'] == 'Fatture di acquisto') && !($original_module['name'] == 'Fatture di vendita' || $original_module['name'] == 'Fatture di acquisto')) {
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Conto').'", "name": "id_conto", "required": 1, "value": "'.$id_conto.'", "ajax-source": "'.($dir == 'entrata' ? 'conti-vendite' : 'conti-acquisti').'" ]}
</div>
</div>';
}
echo '
<div class="clearfix"></div>
<br>
<p>'.tr('Seleziona le righe e le relative quantità da inserire nel documento').'.</p>
<table class="table table-striped table-hover table-condensed">
<tr>
<th>'.tr('Descrizione').'</th>
<th width="10%">'.tr('Q.').'</th>
<th width="15%">'.tr('Q. da evadere').'</th>
<th width="20%">'.tr('Subtot.').'</th>';
if (!empty($options['serials'])) {
echo '
<th width="20%">'.tr('Seriali').'</th>';
}
echo '
</tr>';
$totale = 0.00;
foreach ($righe as $i => $r) {
// Descrizione
echo '
<tr>
<td>
<input type="hidden" name="abilita_serial['.$r['id'].']" value="'.$r['abilita_serial'].'" />
<input type="hidden" id="idarticolo_'.$i.'" name="idarticolo['.$r['id'].']" value="'.$r['idarticolo'].'" />
<input type="hidden" id="descrizione_'.$i.'" name="descrizione['.$r['id'].']" value="'.$r['descrizione'].'" />';
// Checkbox - da evadere?
echo '
<input type="checkbox" checked="checked" id="checked_'.$i.'" name="evadere['.$r['id'].']" value="on" onclick="ricalcola_subtotale_riga('.$i.');" />';
$descrizione = (!empty($r['codice']) ? $r['codice'].' - ' : '').$r['descrizione'];
echo '&nbsp;'.nl2br($descrizione);
echo '
</td>';
// Q.tà rimanente
echo '
<td>
<input type="hidden" id="qtamax_'.$i.'" value="'.($r['qta'] - $r['qta_evasa']).'" />
<input type="hidden" id="um_'.$i.'" name="um['.$r['id'].']" value="'.$r['um'].'" />
<p class="text-center">'.Translator::numberToLocale($r['qta_rimanente']).'</p>
</td>';
// Q.tà da evadere
echo '
<td>
{[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta_rimanente'].'", "extra" : "onkeyup=\"ricalcola_subtotale_riga('.$i.');\"", "decimals": "qta", "min-value": "0", "extra": "'.(($r['is_descrizione']) ? 'readonly' : '').'" ]}
</td>';
// Subtotale
$subtotale = $r['subtotale'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
$sconto = $r['sconto'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
$iva = $r['iva'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
echo '
<td>
<input type="hidden" id="subtot_'.$i.'" name="subtot['.$r['id'].']" value="'.str_replace('.', ',', ($r['subtotale'] / $r['qta'])).'" />
<input type="hidden" id="sconto_'.$i.'" name="sconto['.$r['id'].']" value="'.str_replace('.', ',', ($r['sconto'] / $r['qta'])).'" />
<input type="hidden" id="idiva_'.$i.'" name="idiva['.$r['id'].']" value="'.$r['idiva'].'" />
<input type="hidden" id="iva_'.$i.'" name="iva['.$r['id'].']" value="'.str_replace('.', ',', ($r['iva'] / $r['qta'])).'" />
<big id="subtotale_'.$i.'">'.Translator::numberToLocale($subtotale - $sconto + $iva).' &euro;</big><br/>
<small style="color:#777;" id="subtotaledettagli_'.$i.'">'.Translator::numberToLocale($subtotale - $sconto).' + '.Translator::numberToLocale($iva).'</small>
</td>';
// Seriali
if (!empty($options['serials'])) {
echo '
<td>';
if (!empty($r['abilita_serial'])) {
$query = 'SELECT DISTINCT serial AS id, serial AS descrizione FROM mg_prodotti WHERE dir='.prepare($dir).' AND '.$options['serials']['id_riga'].' = '.prepare($r['id']).' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti AS t WHERE serial IS NOT NULL AND dir='.prepare($dir).' AND '.$options['serials']['condition'].')';
$values = $dbo->fetchArray($query);
if (!empty($values)) {
echo '
{[ "type": "select", "name": "serial['.$r['id'].'][]", "id": "serial_'.$i.'", "multiple": 1, "values": "query='.$query.'", "value": "'.implode(',', array_column($values, 'id')).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]}';
}
}
if (empty($r['abilita_serial']) || empty($values)) {
echo '-';
}
echo '
</td>';
}
echo '
</tr>';
$totale += $subtotale - $sconto + $iva;
}
// Totale
echo '
<tr>
<td colspan="'.(!empty($options['serials']) ? 4 : 3).'" align="right" class="text-right">
<b>'.tr('Totale').':</b>
</td>
<td class="text-right" colspan="2">
<big id="totale">'.Translator::numberToLocale($totale).' &euro;</big>
</td>
</tr>
</table>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" id="submit_btn" class="btn btn-primary pull-right">
<i class="fa fa-plus"></i> '.$options['button'].'
</button>
</div>
</div>
</form>';
} else {
echo '
<p>'.tr('Non ci sono elementi da evadere').'...</p>';
}
echo '
<script src="'.ROOTDIR.'/lib/init.js"></script>';
?>
<script type="text/javascript">
function ricalcola_subtotale_riga(r) {
subtot = $("#subtot_" + r).val();
sconto = $("#sconto_" + r).val();
iva = $("#iva_" + r).val();
qtamax = $("#qtamax_" + r).val() ? $("#qtamax_" + r).val() : 0;
subtot = parseFloat(subtot);
sconto = parseFloat(sconto);
iva = parseFloat(iva);
qtamax = parseFloat(qtamax);
subtot = subtot - sconto;
qta = $("#qta_" + r).val().toEnglish();
// Se inserisco una quantità da evadere maggiore di quella rimanente, la imposto al massimo possibile
if (qta > qtamax) {
qta = qtamax;
$('#qta_' + r).val(qta);
}
// Se tolgo la spunta della casella dell'evasione devo azzerare i conteggi
if (isNaN(qta) || !$('#checked_' + r).is(':checked')) {
qta = 0;
}
$("#serial_" + r).selectClear();
$("#serial_" + r).select2("destroy");
$("#serial_" + r).data('maximum', qta);
start_superselect();
subtotale = (subtot * qta + iva * qta).toLocale();
$("#subtotale_" + r).html(subtotale + " &euro;");
$("#subtotaledettagli_" + r).html((subtot * qta).toLocale() + " + " + (iva * qta).toLocale());
ricalcola_totale();
}
function ricalcola_totale() {
tot_qta = 0;
r = 0;
totale = 0.00;
$('input[id*=qta_]').each(function() {
qta = $(this).val().toEnglish();
if (!$('#checked_' + r).is(':checked') || isNaN(qta)) {
qta = 0;
}
subtot = $("#subtot_" + r).val();
sconto = $("#sconto_" + r).val();
iva = $("#iva_" + r).val();
subtot = parseFloat(subtot);
sconto = parseFloat(sconto);
iva = parseFloat(iva);
subtot = subtot - sconto;
totale += subtot * qta + iva * qta;
r++;
tot_qta += qta;
});
$('#totale').html((totale.toLocale()) + " &euro;");
<?php
if (empty($options['sql']['allow-empty'])) {
echo '
if (tot_qta > 0)
$("#submit_btn").show();
else
$("#submit_btn").hide();';
}
?>
}
</script>

View File

@ -81,7 +81,7 @@ echo '
// Sconto unitario
echo '
<div class="col-md-'.$width.'">
{[ "type": "number", "label": "'.tr('Sconto unitario').'", "name": "sconto", "value": "'.$result['sconto_unitario'].'", "icon-after": "choice|untprc|'.$result['tipo_sconto'].'" ]}
{[ "type": "number", "label": "'.tr('Sconto unitario').'", "name": "sconto", "value": "'.$result['sconto_unitario'].'", "icon-after": "choice|untprc|'.$result['tipo_sconto'].'", "help": "'.tr('Il valore positivo indica uno sconto. Per applicare un rincaro inserire un valore negativo.').'" ]}
</div>
</div>';

View File

@ -67,6 +67,7 @@ if (post('action') == 'init') {
'nome' => 'Amministratori',
]);
// Creazione utente Amministratore
$dbo->insert('zz_users', [
'username' => post('admin_username'),
'password' => Auth::hashPassword(post('admin_password')),
@ -75,6 +76,12 @@ if (post('action') == 'init') {
'idanagrafica' => isset($id_record) ? $id_record : 0,
'enabled' => 1,
]);
// Creazione token API per l'amministratore
$dbo->insert('zz_tokens', [
'id_utente' => $dbo->lastInsertedID(),
'token' => secure_random_string(),
]);
}
if (!$has_settings) {

View File

@ -233,7 +233,7 @@ if (filter('action') == 'do_update') {
$("#progress .info").html($("#progress .info").html() + "<p><strong>'.tr('Aggiornamento _DONE_ di _TODO_ (_VERSION_)', [
'_DONE_' => '" + current + "',
'_TODO_' => '" + count + "',
'_VERSION_' => '" + version + "',
'_VERSION_' => '" + version.trim() + "',
]).'</strong></p>");
}
}

View File

@ -46,7 +46,7 @@ if (!empty($controller_before)) {
* Datatables con record
*/
if (!empty($type) && $type != 'menu' && $type != 'custom') {
$total = App::readQuery($structure);
$total = Util\Query::readQuery($structure);
if (empty($id_plugin) && count(Modules::getSegments($id_module)) > 1) {
echo '

View File

@ -9,7 +9,7 @@ use UnexpectedValueException;
abstract class Article extends Row
{
protected $serialRowID = 'documento';
protected $serialRowID = null;
protected $abilita_movimentazione = true;
protected $qta_movimentazione = 0;

View File

@ -127,6 +127,7 @@ abstract class Description extends Model
*/
protected function customInitCopiaIn($original)
{
$this->is_descrizione = $original->is_descrizione;
}
/**

View File

@ -5,13 +5,16 @@ namespace Common\Components;
use Common\Document;
use Illuminate\Database\Eloquent\Builder;
use Modules\Iva\Aliquota;
use Modules\Ritenute\RitenutaAcconto;
use Modules\Rivalse\RivalsaINPS;
abstract class Row extends Description
{
protected $prezzo_unitario_vendita_riga = null;
protected $casts = [
'qta' => 'float',
//'qta_evasa' => 'float',
];
public static function build(Document $document, $bypass = false)
{
return parent::build($document, true);
@ -44,23 +47,13 @@ abstract class Row extends Description
}
/**
* Restituisce il totale (imponibile + iva + rivalsa_inps + iva_rivalsainps) dell'elemento.
* Restituisce il totale (imponibile + iva) dell'elemento.
*
* @return float
*/
public function getTotaleAttribute()
{
return $this->imponibile_scontato + $this->iva + $this->rivalsa_inps + $this->iva_rivalsa_inps;
}
/**
* Restituisce il netto a pagare (totale - ritenuta_acconto) dell'elemento.
*
* @return float
*/
public function getNettoAttribute()
{
return $this->totale - $this->ritenuta_acconto;
return $this->imponibile_scontato + $this->iva;
}
/**
@ -85,27 +78,6 @@ abstract class Row extends Description
// Attributi della componente
public function getRivalsaINPSAttribute()
{
return $this->imponibile_scontato / 100 * $this->rivalsa->percentuale;
}
public function getIvaRivalsaINPSAttribute()
{
return $this->rivalsa_inps / 100 * $this->aliquota->percentuale;
}
public function getRitenutaAccontoAttribute()
{
$result = $this->imponibile_scontato;
if ($this->calcolo_ritenuta_acconto == 'IMP+RIV') {
$result += $this->rivalsainps;
}
return $result / 100 * $this->ritenuta->percentuale;
}
public function getIvaIndetraibileAttribute()
{
return $this->iva / 100 * $this->aliquota->indetraibile;
@ -141,28 +113,6 @@ abstract class Row extends Description
]);
}
/**
* Imposta l'identificatore della Rivalsa INPS.
*
* @param int $value
*/
public function setIdRivalsaINPSAttribute($value)
{
$this->attributes['idrivalsainps'] = $value;
$this->load('rivalsa');
}
/**
* Imposta l'identificatore della Ritenuta d'Acconto.
*
* @param int $value
*/
public function setIdRitenutaAccontoAttribute($value)
{
$this->attributes['idritenutaacconto'] = $value;
$this->load('ritenuta');
}
/**
* Imposta l'identificatore dell'IVA.
*
@ -210,8 +160,6 @@ abstract class Row extends Description
$this->fixSconto();
$this->fixIva();
$this->fixRitenutaAcconto();
$this->fixRivalsaINPS();
return parent::save($options);
}
@ -221,16 +169,6 @@ abstract class Row extends Description
return $this->belongsTo(Aliquota::class, 'idiva');
}
public function rivalsa()
{
return $this->belongsTo(RivalsaINPS::class, 'idrivalsainps');
}
public function ritenuta()
{
return $this->belongsTo(RitenutaAcconto::class, 'idritenutaacconto');
}
protected static function boot($bypass = false)
{
parent::boot(true);
@ -250,22 +188,6 @@ abstract class Row extends Description
$this->attributes['subtotale'] = $this->imponibile;
}
/**
* Effettua i conti per la Rivalsa INPS.
*/
protected function fixRivalsaINPS()
{
$this->attributes['rivalsainps'] = $this->rivalsa_inps;
}
/**
* Effettua i conti per la Ritenuta d'Acconto, basandosi sul valore del campo calcolo_ritenuta_acconto.
*/
protected function fixRitenutaAcconto()
{
$this->attributes['ritenutaacconto'] = $this->ritenuta_acconto;
}
/**
* Effettua i conti per l'IVA.
*/

View File

@ -27,7 +27,7 @@ abstract class Document extends Model
abstract public function scontoGlobale();
/**
* Calcola l'imponibile della fattura.
* Calcola l'imponibile del documento.
*
* @return float
*/
@ -37,7 +37,7 @@ abstract class Document extends Model
}
/**
* Calcola lo sconto totale della fattura.
* Calcola lo sconto totale del documento.
*
* @return float
*/
@ -47,7 +47,7 @@ abstract class Document extends Model
}
/**
* Calcola l'imponibile scontato della fattura.
* Calcola l'imponibile scontato del documento.
*
* @return float
*/
@ -57,47 +57,17 @@ abstract class Document extends Model
}
/**
* Calcola l'IVA totale della fattura.
* Calcola l'IVA totale del documento.
*
* @return float
*/
public function getIvaAttribute()
{
return $this->calcola('iva', 'iva_rivalsa_inps');
return $this->calcola('iva');
}
/**
* Calcola la rivalsa INPS totale della fattura.
*
* @return float
*/
public function getRivalsaINPSAttribute()
{
return $this->calcola('rivalsa_inps');
}
/**
* Calcola l'iva della rivalsa INPS totale della fattura.
*
* @return float
*/
public function getIvaRivalsaINPSAttribute()
{
return $this->calcola('iva_rivalsa_inps');
}
/**
* Calcola la ritenuta d'acconto totale della fattura.
*
* @return float
*/
public function getRitenutaAccontoAttribute()
{
return $this->calcola('ritenuta_acconto');
}
/**
* Calcola il totale della fattura.
* Calcola il totale del documento.
*
* @return float
*/
@ -106,16 +76,6 @@ abstract class Document extends Model
return $this->calcola('totale');
}
/**
* Calcola il netto a pagare della fattura.
*
* @return float
*/
public function getNettoAttribute()
{
return $this->calcola('netto');
}
/**
* Calcola la spesa totale relativa alla fattura.
*
@ -127,7 +87,7 @@ abstract class Document extends Model
}
/**
* Calcola il guadagno della fattura.
* Calcola il guadagno del documento.
*
* @return float
*/

View File

@ -972,13 +972,23 @@ function start_superselect() {
delay: 250,
data: function (params) {
return {
q: params.term // search term
search: params.term,
page: params.page || 0,
length: params.length || 100,
}
},
processResults: function (data) {
return {
results: data
}
processResults: function (data, params) {
params.page = params.page || 0;
params.length = params.length || 100;
var response = {
results: data.results,
pagination: {
more: (params.page + 1) * params.length < data.recordsFiltered,
}
};
return response;
},
cache: false
},

View File

@ -175,3 +175,60 @@ function logger()
{
return Monolog\Registry::getInstance('logs');
}
/**
* Restituisce il numero indicato formattato secondo la configurazione del sistema.
*
* @param float $number
* @param int $decimals
*
* @return string
*
* @since 2.4.8
*/
function numberFormat($number, $decimals)
{
return Translator::numberToLocale($number, $decimals);
}
/**
* Restituisce il timestamp indicato formattato secondo la configurazione del sistema.
*
* @param string $timestamp
+ *
* @return string
*
* @since 2.4.8
*/
function timestampFormat($timestamp)
{
return Translator::timestampToLocale($timestamp);
}
/**
* Restituisce la data indicata formattato secondo la configurazione del sistema.
*
* @param string $date
*
* @return string
*
* @since 2.4.8
*/
function dateFormat($date)
{
return Translator::dateToLocale($date);
}
/**
* Restituisce l'orario indicato formattato secondo la configurazione del sistema.
*
* @param string $time
*
* @return string
*
* @since 2.4.8
*/
function timeFormat($time)
{
return Translator::timeToLocale($time);
}

View File

@ -77,30 +77,6 @@ if (!function_exists('ends_with')) {
}
}
if (!function_exists('str_replace_once')) {
/**
* Sostituisce la prima occorenza di una determinata stringa.
*
* @param string $str_pattern
* @param string $str_replacement
* @param string $string
*
* @since 2.3
*
* @return string
*/
function str_replace_once($str_pattern, $str_replacement, $string)
{
if (strpos($string, $str_pattern) !== false) {
$occurrence = strpos($string, $str_pattern);
return substr_replace($string, $str_replacement, strpos($string, $str_pattern), strlen($str_pattern));
}
return $string;
}
}
if (!function_exists('str_contains')) {
/**
* Check if a string contains the given string.

View File

@ -98,7 +98,7 @@ echo '
$attachments = [];
if ($template['name'] == 'Fattura Elettronica') {
$attachments = $dbo->fetchArray('SELECT id FROM zz_files WHERE id_module = '.prepare($module['id']).' AND id_record = '.prepare($id_record).' AND category = \'Fattura elettronica\'');
$attachments = $dbo->fetchArray('SELECT id FROM zz_files WHERE id_module = '.prepare($module['id']).' AND id_record = '.prepare($id_record).' AND category = \'Fattura Elettronica\'');
$attachments = array_column($attachments, 'id');
}

View File

@ -50,7 +50,7 @@ if (file_exists($extraction_dir.'/VERSION')) {
$table = 'zz_modules';
$installed = Modules::get($info['name']);
$insert['parent'] = Modules::get($info['parent']);
$insert['parent'] = Modules::get($info['parent'])['id'];
$insert['icon'] = $info['icon'];
}

View File

@ -91,7 +91,7 @@ switch (post('op')) {
// Validazione della Partita IVA
$partita_iva = $anagrafica->partita_iva;
$partita_iva = strlen($partita_iva) == 11 ? $anagrafica->nazione->iso2.$partita_iva : $partita_iva;
$partita_iva = is_numeric($partita_iva) ? $anagrafica->nazione->iso2.$partita_iva : $partita_iva;
$check_vat_number = Validate::isValidVatNumber($partita_iva);
if (empty($check_vat_number)) {
@ -188,10 +188,10 @@ switch (post('op')) {
case 'delete':
// Se l'anagrafica non è l'azienda principale, la disattivo
if (!in_array($id_azienda, $tipi_anagrafica)) {
$dbo->query('UPDATE an_anagrafiche SET deleted_at = NOW() WHERE idanagrafica = '.prepare($id_record).Modules::getAdditionalsQuery($id_module));
$dbo->query('UPDATE an_anagrafiche SET deleted_at = NOW() WHERE idanagrafica = '.prepare($id_record));
// Se l'anagrafica è collegata ad un utente lo disabilito
$dbo->query('UPDATE zz_users SET enabled = 0 WHERE idanagrafica = '.prepare($id_record).Modules::getAdditionalsQuery($id_module));
$dbo->query('UPDATE zz_users SET enabled = 0 WHERE idanagrafica = '.prepare($id_record));
flash()->info(tr('Anagrafica eliminata!'));
}

View File

@ -23,13 +23,16 @@ echo '
</div>
<div class="row">
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Cognome').'", "name": "cognome", "required": 0 ]}
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Nome').'", "name": "nome", "required": 0 ]}
</div>
<div class="col-md-6">
{[ "type": "text", "label": "'.tr('Cognome').'", "name": "cognome", "required": 0 ]}
</div>
</div>';
echo '

View File

@ -87,7 +87,7 @@ switch ($resource) {
$search_fields[] = 'provincia LIKE '.prepare('%'.$search.'%');
}
$results = AJAX::completeResults($query, $where, $filter, $search, $custom);
$results = AJAX::selectResults($query, $where, $filter, $search, $limit, $custom);
// Evidenzia l'agente di default
if ($superselect['idanagrafica']) {

View File

@ -335,9 +335,9 @@ if (!empty($google)) {
{[ "type": "select", "label": "<?php echo tr('Listino articoli'); ?>", "name": "idlistino_vendite", "values": "query=SELECT id, nome AS descrizione FROM mg_listini ORDER BY nome ASC", "value": "$idlistino_vendite$", "extra": "<?php echo ($cliente) ? '' : 'readonly'; ?>" ]}
</div>
<div class="col-md-6">
{[ "type": "select", "label": "<?php echo tr('Indirizzo di fatturazione'); ?>", "name": "idsede_fatturazione", "values": "query=SELECT id, IF(citta = '', nomesede, CONCAT_WS(', ', nomesede, citta)) AS descrizione FROM an_sedi WHERE idanagrafica='<?php echo $id_record; ?>' UNION SELECT '0' AS id, 'Sede legale' AS descrizione ORDER BY descrizione", "value": "$idsede_fatturazione$" , "extra": "<?php echo ($cliente) ? '' : 'readonly'; ?>" ]}
</div>
<div class="col-md-6">
{[ "type": "select", "label": "<?php echo tr('Indirizzo di fatturazione'); ?>", "name": "idsede_fatturazione", "values": "query=SELECT id, IF(citta = '', nomesede, CONCAT_WS(', ', nomesede, citta)) AS descrizione FROM an_sedi WHERE idanagrafica='<?php echo $id_record; ?>' UNION SELECT '0' AS id, 'Sede legale' AS descrizione ORDER BY descrizione", "value": "$idsede_fatturazione$" , "extra": "<?php echo ($cliente) ? '' : 'readonly'; ?>" ]}
</div>
</div>
<div class="row">
@ -349,31 +349,27 @@ if (!empty($google)) {
{[ "type": "select", "label": "<?php echo tr('Agente principale'); ?>", "name": "idagente", "values": "query=SELECT an_anagrafiche.idanagrafica AS id, IF(deleted_at IS NOT NULL, CONCAT(ragione_sociale, ' (Eliminato)'), ragione_sociale ) AS descrizione FROM an_anagrafiche INNER JOIN (an_tipianagrafiche_anagrafiche INNER JOIN an_tipianagrafiche ON an_tipianagrafiche_anagrafiche.idtipoanagrafica=an_tipianagrafiche.idtipoanagrafica) ON an_anagrafiche.idanagrafica=an_tipianagrafiche_anagrafiche.idanagrafica WHERE (descrizione='Agente' AND deleted_at IS NULL)<?php echo isset($record['idagente']) ? 'OR (an_anagrafiche.idanagrafica = '.prepare($record['idagente']).' AND deleted_at IS NOT NULL) ' : ''; ?>ORDER BY ragione_sociale", "value": "$idagente$", "extra": "<?php echo ($cliente) ? '' : 'readonly'; ?>" ]}
</div>
</div>
<div class="row">
<div class="col-md-6">
<?php
<?php
// Collegamento con il conto
$conto = $dbo->fetchOne('SELECT co_pianodeiconti2.numero as numero, co_pianodeiconti3.numero as numero_conto, co_pianodeiconti3.descrizione as descrizione FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = '.prepare($record['idconto_cliente']));
// Collegamento con il conto
$conto = $dbo->fetchOne('SELECT co_pianodeiconti2.numero as numero, co_pianodeiconti3.numero as numero_conto, co_pianodeiconti3.descrizione as descrizione FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = '.prepare($record['idconto_cliente']));
/*echo '
<p>'.tr('Piano dei conti collegato: _NAME_', [
'_NAME_' => $conto['numero'].'.'.$conto['numero_conto'].' '.$conto['descrizione'],
]).Modules::link('Piano dei conti', null, '').'</p>';*/
if (!empty($conto['numero_conto'])) {
$piano_dei_conti_cliente = tr('_NAME_', [
'_NAME_' => $conto['numero'].'.'.$conto['numero_conto'].' '.$conto['descrizione'],
]);
'_NAME_' => $conto['numero'].'.'.$conto['numero_conto'].' '.$conto['descrizione'],
]);
echo Modules::link('Piano dei conti', null, null, null, 'class="pull-right"');
} else {
$piano_dei_conti_cliente = tr('Nessuno');
} ?>
{[ "type": "select", "label": "<?php echo tr('Piano dei conti cliente'); ?>", "name": "piano_dei_conti_cliente", "values": "list=\"\": \"<?php echo $piano_dei_conti_cliente; ?>\"", "readonly": 1, "value": "", "extra": "" ]}
</div>
</div>
{[ "type": "select", "label": "<?php echo tr('Piano dei conti cliente'); ?>", "name": "piano_dei_conti_cliente", "values": "list=\"\": \"<?php echo $piano_dei_conti_cliente; ?>\"", "readonly": 1, "value": "", "extra": "" ]}
</div>
</div>
</div>

View File

@ -16,7 +16,7 @@ if (isset($id_record)) {
(SELECT GROUP_CONCAT(an_tipianagrafiche.idtipoanagrafica) FROM an_tipianagrafiche INNER JOIN an_tipianagrafiche_anagrafiche ON an_tipianagrafiche.idtipoanagrafica=an_tipianagrafiche_anagrafiche.idtipoanagrafica WHERE idanagrafica=an_anagrafiche.idanagrafica) AS idtipianagrafica,
(SELECT GROUP_CONCAT(idagente) FROM an_anagrafiche_agenti WHERE idanagrafica=an_anagrafiche.idanagrafica) AS idagenti,
(SELECT GROUP_CONCAT(descrizione) FROM an_tipianagrafiche INNER JOIN an_tipianagrafiche_anagrafiche ON an_tipianagrafiche.idtipoanagrafica=an_tipianagrafiche_anagrafiche.idtipoanagrafica WHERE idanagrafica=an_anagrafiche.idanagrafica) AS tipianagrafica
FROM an_anagrafiche WHERE idanagrafica='.prepare($id_record).' '.Modules::getAdditionalsQuery($id_module));
FROM an_anagrafiche WHERE idanagrafica='.prepare($id_record));
// Cast per latitudine e longitudine
if (!empty($record)) {

View File

@ -46,6 +46,7 @@ class Anagrafica extends Model
$codice = Generator::generate(setting('Formato codice anagrafica'), $ultimo['codice']);
$model->codice = $codice;
$model->id_ritenuta_acconto_vendite = setting("Percentuale ritenuta d'acconto");
$model->save();
$model->tipologie = $tipologie;

View File

@ -151,7 +151,7 @@ switch (post('op')) {
preg_match("/(.*?)([\d]*$)/", $serial__end, $m);
$serial_end = intval($m[2]);
$n_serial = abs($serial_end - $serial_start) + 1;
$serial_prefix = str_replace($serial_end, '', $serial__end);
$serial_prefix = rtrim($serial__end,$serial_end);
$serial_pad_length = strlen($serial__end) - strlen($serial_prefix);
// Altro

View File

@ -4,7 +4,62 @@ include_once __DIR__.'/../../../core.php';
switch ($resource) {
case 'articoli':
$query = 'SELECT mg_articoli.*, (SELECT CONCAT(co_pianodeiconti2.numero, ".", co_pianodeiconti3.numero, " ", co_pianodeiconti3.descrizione) FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = idconto_vendita) AS idconto_vendita_title, (SELECT CONCAT(co_pianodeiconti2.numero, ".", co_pianodeiconti3.numero, " ", co_pianodeiconti3.descrizione) FROM co_pianodeiconti3 INNER JOIN co_pianodeiconti2 ON co_pianodeiconti3.idpianodeiconti2=co_pianodeiconti2.id WHERE co_pianodeiconti3.id = idconto_acquisto) AS idconto_acquisto_title, co_iva.descrizione AS iva_vendita FROM mg_articoli LEFT OUTER JOIN co_iva ON mg_articoli.idiva_vendita=co_iva.id |where| ORDER BY mg_articoli.id_categoria ASC, mg_articoli.id_sottocategoria ASC';
$query = 'SELECT
mg_articoli.id,
mg_articoli.codice,
mg_articoli.descrizione,
mg_articoli.um,
mg_articoli.idiva_vendita,
mg_articoli.idconto_vendita,
mg_articoli.idconto_acquisto,
mg_articoli.prezzo_vendita,
mg_articoli.prezzo_acquisto,
categoria.`nome` AS categoria,
sottocategoria.`nome` AS sottocategoria,
co_iva.descrizione AS iva_vendita,
CONCAT(conto_vendita_categoria .numero, ".", conto_vendita_sottocategoria.numero, " ", conto_vendita_sottocategoria.descrizione) AS idconto_vendita_title,
CONCAT(conto_acquisto_categoria .numero, ".", conto_acquisto_sottocategoria.numero, " ", conto_acquisto_sottocategoria.descrizione) AS idconto_acquisto_title
FROM mg_articoli
LEFT JOIN co_iva ON mg_articoli.idiva_vendita = co_iva.id
LEFT JOIN `mg_categorie` AS categoria ON `categoria`.`id` = `mg_articoli`.`id_categoria`
LEFT JOIN `mg_categorie` AS sottocategoria ON `sottocategoria`.`id` = `mg_articoli`.`id_sottocategoria`
LEFT JOIN co_pianodeiconti3 AS conto_vendita_sottocategoria ON conto_vendita_sottocategoria.id=mg_articoli.idconto_vendita
LEFT JOIN co_pianodeiconti2 AS conto_vendita_categoria ON conto_vendita_sottocategoria.idpianodeiconti2=conto_vendita_categoria.id
LEFT JOIN co_pianodeiconti3 AS conto_acquisto_sottocategoria ON conto_acquisto_sottocategoria.id=mg_articoli.idconto_acquisto
LEFT JOIN co_pianodeiconti2 AS conto_acquisto_categoria ON conto_acquisto_sottocategoria.idpianodeiconti2=conto_acquisto_categoria.id
|where| ORDER BY mg_articoli.id_categoria ASC, mg_articoli.id_sottocategoria ASC';
foreach ($elements as $element) {
$filter[] = 'mg_articoli.id='.prepare($element);
}
$where[] = 'attivo = 1';
if (!empty($superselect['dir']) && $superselect['dir'] == 'entrata') {
//$where[] = '(qta > 0 OR servizio = 1)';
}
if (!empty($search)) {
$search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%');
}
$custom = [
'id' => 'id',
'codice' => 'codice',
'descrizione' => 'descrizione',
'um' => 'um',
'idiva_vendita' => 'idiva_vendita',
'iva_vendita' => 'iva_vendita',
'idconto_vendita' => 'idconto_vendita',
'idconto_vendita_title' => 'idconto_vendita_title',
'idconto_acquisto' => 'idconto_acquisto',
'idconto_acquisto_title' => 'idconto_acquisto_title',
'prezzo_acquisto' => 'prezzo_acquisto',
'prezzo_vendita' => 'prezzo_vendita',
];
$data = AJAX::selectResults($query, $where, $filter, $search_fields, $limit, $custom);
$rs = $data['results'];
// Individuazione di eventuali listini
if (!empty($superselect['dir']) && !empty($superselect['idanagrafica'])) {
@ -21,45 +76,22 @@ switch ($resource) {
$idiva_predefinita = get_var('Iva predefinita');
$iva_predefinita = $dbo->fetchOne('SELECT descrizione FROM co_iva WHERE id='.prepare($idiva_predefinita))['descrizione'];
foreach ($elements as $element) {
$filter[] = 'mg_articoli.id='.prepare($element);
}
$where[] = 'attivo = 1';
if (!empty($superselect['dir']) && $superselect['dir'] == 'entrata') {
//$where[] = '(qta > 0 OR servizio = 1)';
}
if (!empty($search)) {
$search_fields[] = 'mg_articoli.descrizione LIKE '.prepare('%'.$search.'%');
$search_fields[] = 'mg_articoli.codice LIKE '.prepare('%'.$search.'%');
}
if (!empty($search_fields)) {
$where[] = '('.implode(' OR ', $search_fields).')';
}
if (!empty($filter)) {
$where[] = '('.implode(' OR ', $filter).')';
}
$wh = '';
if (count($where) != 0) {
$wh = 'WHERE '.implode(' AND ', $where);
}
$query = str_replace('|where|', $wh, $query);
$prev = -1;
$rs = $dbo->fetchArray($query);
$previous_category = -1;
$previous_subcategory = -1;
foreach ($rs as $r) {
if ($prev != $r['id_sottocategoria']) {
$categoria = $dbo->fetchOne('SELECT `nome` FROM `mg_categorie` WHERE `id`='.prepare($r['id_categoria']))['nome'];
if ($previous_category != $r['categoria'] || $previous_subcategory != $r['sottocategoria']) {
$previous_category = $r['categoria'];
$previous_subcategory = $r['sottocategoria'];
$sottocategoria = $dbo->fetchOne('SELECT `nome` FROM `mg_categorie` WHERE `id`='.prepare($r['id_sottocategoria']));
$sottocategoria = isset($sottocategoria['nome']) ? $sottocategoria['nome'] : null;
$text = '<i>'.tr('Nessuna categoria').'</i>';
if (!empty($r['categoria'])) {
$text = $r['categoria'].' ('.(!empty($r['sottocategoria']) ? $r['sottocategoria'] : '-').')';
}
$prev = $r['id_sottocategoria'];
$results[] = ['text' => $categoria.' ('.(!empty($r['id_sottocategoria']) ? $sottocategoria : '-').')', 'children' => []];
$results[] = [
'text' => $text,
'children' => [],
];
}
// Iva dell'articolo
@ -101,6 +133,11 @@ switch ($resource) {
];
}
$results = [
'results' => $results,
'recordsFiltered' => $data['recordsFiltered'],
];
break;
case 'prodotti_lotti':

View File

@ -74,6 +74,19 @@ switch (post('op')) {
]);
}
}
// Codice --> ID IVA vendita
if (!empty($data[$key]['idiva_vendita'])) {
$rs_iva = $dbo->select('co_iva', 'id', [
'codice' => $data[$key]['idiva_vendita'],
]);
if (!empty($rs_iva[0]['id'])) {
$data[$key]['idiva_vendita'] = $rs_iva[0]['id'];
};
}
// Insert o update
$insert = true;
@ -165,6 +178,14 @@ return [
'id_categoria',
'idcategoria',
],
],
[
'field' => 'idiva_vendita',
'label' => 'Codice IVA vendita',
'names' => [
'Codice IVA vendita',
'idiva_vendita',
],
],
[
'field' => 'note',

View File

@ -8,11 +8,7 @@ if (isset($id_record)) {
include __DIR__.'/init.php';
}
?><form action="editor.php?id_module=$id_module$<?php
if (isset($id_record)) {
echo '&id_record='.$id_record;
}
?>" method="post" id="add-form">
?><form action="" method="post" id="add-form">
<input type="hidden" name="backto" value="record-edit">
<?php

View File

@ -10,13 +10,11 @@ switch ($resource) {
$filter[] = 'id='.prepare($element);
}
$where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']);
if (empty($elements)) {
$where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']);
$stato = !empty($superselect['stato']) ? $superselect['stato'] : 'pianificabile';
$where[] = 'idstato IN (SELECT `id` FROM co_staticontratti WHERE '.$stato.' = 1)';
if (!empty($superselect['non_fatturato'])) {
$where[] = 'id NOT IN (SELECT idcontratto FROM co_righe_documenti WHERE idcontratto IS NOT NULL)';
$stato = !empty($superselect['stato']) ? $superselect['stato'] : 'pianificabile';
$where[] = 'idstato IN (SELECT `id` FROM co_staticontratti WHERE '.$stato.' = 1)';
}
if (!empty($search)) {

View File

@ -3,15 +3,18 @@
include_once __DIR__.'/../../core.php';
$rs_documento = $dbo->fetchArray('SELECT * FROM co_righe_contratti WHERE idcontratto='.prepare($id_record));
/* permetto di fatturare il contratto solo se contiene righe e si trova in uno stato fatturabile */
echo '
<button type="button" class="btn btn-info" '.((($record['fatturabile']) and (sizeof($rs_documento) > 0)) ? '' : 'disabled')." onclick=\"if( confirm('Creare una fattura per questo contratto?') ){fattura_da_contratto();}\">
<i class=\"fa fa-magic\"></i> ".tr('Crea fattura').'...
<button type="button" class="btn btn-info '.(($record['fatturabile'] && !empty($rs_documento)) ? '' : 'disabled').'" data-href="'.$structure->fileurl('crea_documento.php').'?id_module='.$id_module.'&id_record='.$id_record.'&documento=fattura" data-toggle="modal" data-title="'.tr('Crea fattura').'">
<i class="fa fa-magic"></i> '.tr('Crea fattura').'
</button>';
if ($record['rinnovabile']) {
$rinnova = !empty($record['data_accettazione']) && !empty($record['data_conclusione']) && $record['data_accettazione'] != '0000-00-00' && $record['data_conclusione'] != '0000-00-00' && $record['pianificabile'];
$stati_pianificabili = $dbo->fetchOne('SELECT GROUP_CONCAT(`descrizione` SEPARATOR ", ") AS stati_pianificabili FROM `co_staticontratti` WHERE `pianificabile` = 1')['stati_pianificabili'];
echo '
<div class="tip" data-toggle="tooltip" title="'.tr('Il contratto è rinnovabile se sono definite le date di accettazione e conclusione e si trova in uno stato di questi stati: '.$stati_pianificabili).'" style="display:inline;">
<button type="button" class="btn btn-warning ask '.($rinnova ? '' : 'disabled').'" data-backto="record-edit" data-op="renew" data-msg="'.tr('Rinnovare questo contratto?').'" data-button="Rinnova" data-class="btn btn-lg btn-warning" '.($rinnova ? '' : 'disabled').'>

View File

@ -0,0 +1,27 @@
<?php
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
$options = [
'op' => 'add_contratto',
'id_importazione' => 'id_contratto',
'final_module' => 'Fatture di vendita',
'original_module' => $module['name'],
'sql' => [
'table' => 'co_contratti',
'rows' => 'co_righe_contratti',
'id_rows' => 'idcontratto',
],
'button' => tr('Aggiungi'),
'dir' => 'entrata',
'create_document' => true,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);

View File

@ -134,7 +134,7 @@ if ($record['stato'] == 'Emessa') {
</div>
<!-- Fatturazione Elettronica -->
<div class="panel panel-primary <?php echo (($record['tipo_anagrafica']) == 'Ente pubblico' or ($record['tipo_anagrafica']) == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel panel-primary <?php echo ($record['tipo_anagrafica'] == 'Ente pubblico' || $record['tipo_anagrafica'] == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Dati appalto'); ?></h3>
</div>
@ -382,12 +382,6 @@ if (!empty($record['idcontratto_prev'])) {
{( "name": "log_email", "id_module": "$id_module$", "id_record": "$id_record$" )}
<form action='<?php echo $rootdir; ?>/editor.php?id_module=<?php echo Modules::get('Fatture di vendita')['id']; ?>' method='post' id='form_creafattura'>
<input type="hidden" name="backto" value="record-edit">
<input type='hidden' name='op' value='fattura_da_contratto'>
<input type="hidden" name="id_record" value="<?php echo $id_record; ?>">
</form>
<script type="text/javascript">
$(document).ready(function(){
$('#data_accettazione').on("dp.change", function(){
@ -410,10 +404,6 @@ if (!empty($record['idcontratto_prev'])) {
$("#data_rifiuto").trigger("dp.change");
});
function fattura_da_contratto(){
$('#form_creafattura').submit();
}
$('#idanagrafica_c').change( function(){
session_set('superselect,idanagrafica', $(this).val(), 0);

View File

@ -3,5 +3,11 @@
include_once __DIR__.'/../../core.php';
if (isset($id_record)) {
$record = $dbo->fetchOne('SELECT *, (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_contratti.idanagrafica) AS tipo_anagrafica, (SELECT fatturabile FROM co_staticontratti WHERE id=idstato) AS fatturabile, (SELECT pianificabile FROM co_staticontratti WHERE id=idstato) AS pianificabile, (SELECT descrizione FROM co_staticontratti WHERE id=idstato) AS stato, (SELECT GROUP_CONCAT(my_impianti_contratti.idimpianto) FROM my_impianti_contratti WHERE idcontratto = co_contratti.id) AS idimpianti FROM co_contratti WHERE id='.prepare($id_record).Modules::getAdditionalsQuery($id_module));
$record = $dbo->fetchOne('SELECT *,
(SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_contratti.idanagrafica) AS tipo_anagrafica,
(SELECT fatturabile FROM co_staticontratti WHERE id=idstato) AS fatturabile,
(SELECT pianificabile FROM co_staticontratti WHERE id=idstato) AS pianificabile,
(SELECT descrizione FROM co_staticontratti WHERE id=idstato) AS stato,
(SELECT GROUP_CONCAT(my_impianti_contratti.idimpianto) FROM my_impianti_contratti WHERE idcontratto = co_contratti.id) AS idimpianti
FROM co_contratti WHERE id='.prepare($id_record));
}

View File

@ -21,7 +21,22 @@ $totale = 0;
$totale_stato = [];
// Tabella con riepilogo interventi
$rsi = $dbo->fetchArray('SELECT *, in_interventi.id, (SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio, (SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore, (SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km FROM co_promemoria INNER JOIN in_interventi ON co_promemoria.idintervento=in_interventi.id WHERE co_promemoria.idcontratto='.prepare($id_record).' ORDER BY co_promemoria.idintervento DESC');
$rsi = $dbo->fetchArray('SELECT in_interventi.id, in_interventi.codice,
(SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio,
(SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore,
(SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km
FROM co_promemoria
INNER JOIN in_interventi ON co_promemoria.idintervento=in_interventi.id
WHERE co_promemoria.idcontratto='.prepare($id_record).'
UNION
SELECT in_interventi.id, in_interventi.codice,
(SELECT MIN(orario_inizio) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS inizio,
(SELECT SUM(ore) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS ore,
(SELECT MIN(km) FROM in_interventi_tecnici WHERE idintervento=in_interventi.id) AS km
FROM in_interventi
WHERE id_contratto = '.prepare($id_record).'
ORDER BY id DESC');
if (!empty($rsi)) {
echo '
<table class="table table-bordered table-condensed">

View File

@ -38,10 +38,12 @@ foreach ($rs as $r) {
// Q.tà
echo '
<td class="text-right">';
<td class="text-center">';
if (empty($r['is_descrizione'])) {
echo '
'.Translator::numberToLocale($r['qta'], 'qta');
<big>'.Translator::numberToLocale($r['qta'] - $r['qta_evasa'], 'qta').'</big>
<br><small>('.tr('Q. iniziale').': '.Translator::numberToLocale($r['qta'], 'qta').')</small>';
}
echo '
</td>';

View File

@ -5,6 +5,7 @@ namespace Modules\Contratti;
use Carbon\Carbon;
use Common\Document;
use Modules\Anagrafiche\Anagrafica;
use Modules\Interventi\Intervento;
use Modules\Interventi\TipoSessione;
use Traits\RecordTrait;
use Util\Generator;
@ -138,6 +139,11 @@ class Contratto extends Document
return $this->hasOne(Components\Sconto::class, 'idcontratto');
}
public function interventi()
{
return $this->hasMany(Intervento::class, 'id_contratto');
}
// Metodi statici
/**

View File

@ -28,7 +28,13 @@ include_once __DIR__.'/../../core.php';
</div>
</div>
<!-- PULSANTI -->
<?php
include $module->filepath('content-info.php');
?>
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary"><i class="fa fa-plus"></i> <?php echo tr('Aggiungi'); ?></button>

View File

@ -0,0 +1,37 @@
<?php
echo '
<!-- Istruzioni per il contenuto -->
<div class="box box-info">
<div class="box-header">
<h3 class="box-title">'.tr('Istruzioni per il campo _FIELD_', [
'_FIELD_' => tr('Contenuto'),
]).'</h3>
</div>
<div class="box-body">
<p>'.tr('Le seguenti sequenze di testo vengono sostituite nel seguente modo').':</p>
<ul>';
$list = [
'label' => tr('Nome'),
'name' => tr('Nome HTML'),
];
foreach ($list as $key => $value) {
echo '
<li>'.tr('_TEXT_ con il valore del campo "_FIELD_"', [
'_TEXT_' => '<code>|'.$key.'|</code>',
'_FIELD_' => $value,
]).'</li>';
}
echo '
<li>'.tr('_TEXT_ con il valore impostato per il record', [
'_TEXT_' => '<code>|value|</code>',
]).'</li>';
echo '
</ul>
</div>
</div>';

View File

@ -45,40 +45,11 @@ include_once __DIR__.'/../../core.php';
</div>
</form>
<!-- Istruzioni per il contenuto -->
<div class="box box-info">
<div class="box-header">
<h3 class="box-title"><?php echo tr('Istruzioni per il campo _FIELD_', [
'_FIELD_' => tr('Contenuto'),
]); ?></h3>
</div>
<div class="box-body">
<p><?php echo tr('Le seguenti sequenze di testo vengono sostituite nel seguente modo'); ?>:</p>
<ul>
<?php
$list = [
'name' => tr('Nome'),
'html_name' => tr('Nome HTML'),
];
foreach ($list as $key => $value) {
echo '
<li>'.tr('_TEXT_ con il valore del campo "_FIELD_"', [
'_TEXT_' => '<code>|'.$key.'|</code>',
'_FIELD_' => $value,
]).'</li>';
}
echo '
<li>'.tr('_TEXT_ con il valore impostato per il record', [
'_TEXT_' => '<code>|value|</code>',
]).'</li>';
include $module->filepath('content-info.php');
?>
</ul>
</div>
</div>
<hr>

View File

@ -198,82 +198,67 @@ switch (post('op')) {
break;
// Creazione ddt da ordine
case 'ddt_da_ordine':
$totale_ordine = 0.00;
$data = post('data');
$idanagrafica = post('idanagrafica');
$idsede = post('idsede');
$idpagamento = post('idpagamento');
$idconto = post('idconto');
$idordine = post('idordine');
// Aggiunta di un ordine in ddt
case 'add_ordine':
$ordine = \Modules\Ordini\Ordine::find(post('id_ordine'));
// Creazione DDT
$anagrafica = Anagrafica::find($idanagrafica);
$tipo = Tipo::where('dir', $dir)->first();
// Creazione della fattura al volo
if (post('create_document') == 'on') {
$tipo = Tipo::where('dir', $dir)->first();
$ddt = DDT::build($anagrafica, $tipo, $data);
$id_record = $ddt->id;
$ddt = DDT::build($ordine->anagrafica, $tipo, post('data'));
$ddt->idpagamento = $ordine->idpagamento;
$ddt->save();
// Lettura di tutte le righe della tabella in arrivo
foreach (post('qta_da_evadere') as $idriga => $value) {
// Processo solo le righe da evadere
if (post('evadere')[$idriga] == 'on') {
$idarticolo = post('idarticolo')[$idriga];
$descrizione = post('descrizione')[$idriga];
$id_record = $ddt->id;
}
$qta = post('qta_da_evadere')[$idriga];
$um = post('um')[$idriga];
$abilita_serial = post('abilita_serial')[$idriga];
$parziale = false;
$righe = $ordine->getRighe();
foreach ($righe as $riga) {
if (post('evadere')[$riga->id] == 'on') {
$qta = post('qta_da_evadere')[$riga->id];
$subtot = post('subtot')[$idriga] * $qta;
$sconto = post('sconto')[$idriga];
$sconto = $sconto * $qta;
$idiva = post('idiva')[$idriga];
$iva = post('iva')[$idriga] * $qta;
$qprc = 'SELECT tipo_sconto, sconto_unitario FROM or_righe_ordini WHERE id='.prepare($idriga);
$rsprc = $dbo->fetchArray($qprc);
$sconto_unitario = $rsprc[0]['sconto_unitario'];
$tipo_sconto = $rsprc[0]['tipo_sconto'];
// Calcolo l'iva indetraibile
$q = 'SELECT descrizione, indetraibile FROM co_iva WHERE id='.prepare($idiva);
$rs = $dbo->fetchArray($q);
$iva_indetraibile = $iva / 100 * $rs[0]['indetraibile'];
// Inserisco la riga in ddt
$dbo->query('INSERT INTO dt_righe_ddt(idddt, idordine, idarticolo, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, abilita_serial, `order`) VALUES('.prepare($id_record).', '.prepare($idordine).', '.prepare($idarticolo).', '.prepare($idiva).', '.prepare($rs[0]['descrizione']).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', '.prepare($abilita_serial).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM dt_righe_ddt AS t WHERE idddt='.prepare($id_record).'))');
$riga = $dbo->lastInsertedID();
$copia = $riga->copiaIn($ddt, $qta);
// Aggiornamento seriali dalla riga dell'ordine
$serials = is_array(post('serial')[$idriga]) ? post('serial')[$idriga] : [];
$serials = array_clean($serials);
if ($copia->isArticolo()) {
$copia->movimenta($copia->qta);
$dbo->sync('mg_prodotti', ['id_riga_ddt' => $riga, 'dir' => $dir, 'id_articolo' => $idarticolo], ['serial' => $serials]);
$serials = is_array(post('serial')[$riga->id]) ? post('serial')[$riga->id] : [];
// Scalo la quantità dall'ordine
$dbo->query('UPDATE or_righe_ordini SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idriga));
// Movimento il magazzino
if (!empty($idarticolo)) {
// vendita
if ($dir == 'entrata') {
add_movimento_magazzino($idarticolo, -$qta, ['idddt' => $id_record]);
}
// acquisto
else {
add_movimento_magazzino($idarticolo, $qta, ['idddt' => $id_record]);
}
$copia->serials = $serials;
}
$copia->save();
}
if ($riga->qta != $riga->qta_evasa) {
$parziale = true;
}
}
// Aggiornamento sconto
if (post('evadere')[$ordine->scontoGlobale->id] == 'on') {
$ddt->tipo_sconto_globale = $ordine->tipo_sconto_globale;
$ddt->sconto_globale = $ordine->tipo_sconto_globale == 'PRC' ? $ordine->sconto_globale : $ordine->sconto_globale;
$ddt->save();
$ddt->updateSconto();
}
// Impostazione del nuovo stato
$descrizione = $parziale ? 'Parzialmente evaso' : 'Evaso';
$stato = \Modules\Ordini\Stato::where('descrizione', $descrizione)->first();
$ordine->stato()->associate($stato);
$ordine->save();
ricalcola_costiagg_ddt($id_record);
flash()->info(tr('Creato un nuovo ddt!'));
flash()->info(tr('Ordine _NUM_ aggiunto!', [
'_NUM_' => $ordine->numero,
]));
break;
// Scollegamento articolo da ddt
@ -489,71 +474,6 @@ switch (post('op')) {
}
break;
// aggiungi righe da ordine
case 'add_ordine':
$idordine = post('iddocumento');
// Lettura di tutte le righe della tabella in arrivo
foreach (post('qta_da_evadere') as $i => $value) {
// Processo solo le righe da evadere
if (post('evadere')[$i] == 'on') {
$idrigaordine = $i;
$idarticolo = post('idarticolo')[$i];
$descrizione = post('descrizione')[$i];
$qta = post('qta_da_evadere')[$i];
$um = post('um')[$i];
$subtot = post('subtot')[$i] * $qta;
$sconto = post('sconto')[$i];
$sconto = $sconto * $qta;
$qprc = 'SELECT tipo_sconto, sconto_unitario FROM or_righe_ordini WHERE id='.prepare($idrigaordine);
$rsprc = $dbo->fetchArray($qprc);
$sconto_unitario = $rsprc[0]['sconto_unitario'];
$tipo_sconto = $rsprc[0]['tipo_sconto'];
$idiva = post('idiva')[$i];
// Calcolo l'iva indetraibile
$q = 'SELECT percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva);
$rs = $dbo->fetchArray($q);
$iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $rs[0]['indetraibile'];
// Leggo la descrizione iva
$query = 'SELECT * FROM co_iva WHERE id='.prepare($idiva);
$rs = $dbo->fetchArray($query);
$desc_iva = $rs[0]['descrizione'];
// Se sto aggiungendo un articolo uso la funzione per inserirlo e incrementare la giacenza
if (!empty($idarticolo)) {
$idiva_acquisto = $idiva;
$prezzo_acquisto = $subtot;
$riga = add_articolo_inddt($id_record, $idarticolo, $descrizione, $idiva, $qta, $um, $prezzo_acquisto, $sconto, $sconto_unitario, $tipo_sconto);
// Lettura lotto, serial, altro dalla riga dell'ordine
$dbo->query('INSERT INTO mg_prodotti (id_riga_documento, id_articolo, dir, serial, lotto, altro) SELECT '.prepare($riga).', '.prepare($idarticolo).', '.prepare($dir).', serial, lotto, altro FROM mg_prodotti AS t WHERE id_riga_ordine='.prepare($idrigaordine));
}
// Inserimento riga normale
elseif ($qta != 0) {
$query = 'INSERT INTO dt_righe_ddt(idddt, idarticolo, descrizione, idordine, idiva, desc_iva, iva, iva_indetraibile, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($descrizione).', '.prepare($idordine).', '.prepare($idiva).', '.prepare($desc_iva).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM co_righe_documenti AS t WHERE iddocumento='.prepare($id_record).'))';
$dbo->query($query);
}
// Scalo la quantità dall ordine
$dbo->query('UPDATE or_righe_ordini SET qta_evasa = qta_evasa+'.$qta.' WHERE id='.prepare($idrigaordine));
}
}
ricalcola_costiagg_ddt($id_record);
flash()->info(tr('Aggiunti nuovi articoli in ddt!'));
break;
}
// Aggiornamento stato degli ordini presenti in questa fattura in base alle quantità totali evase

View File

@ -4,41 +4,88 @@ include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
if ($module['name'] == 'Ddt di vendita') {
$dir = 'entrata';
$module_origin = 'Ordini cliente';
} else {
$dir = 'uscita';
$module_origin = 'Ordini fornitore';
$dir = ($module['name'] == 'Ddt di vendita') ? 'entrata' : 'uscita';
if (get('op')) {
$options = [
'op' => 'add_ordine',
'id_importazione' => 'id_ordine',
'final_module' => $module['name'],
'original_module' => $module['name'] == 'Ddt di vendita' ? 'Ordini cliente' : 'Ordini fornitore',
'sql' => [
'table' => 'or_ordini',
'rows' => 'or_righe_ordini',
'id_rows' => 'idordine',
],
'serials' => [
'id_riga' => 'id_riga_ddt',
'condition' => '(id_riga_documento IS NOT NULL)',
],
'button' => tr('Aggiungi'),
'dir' => $dir,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
return;
}
$info = $dbo->fetchOne('SELECT * FROM dt_ddt WHERE id='.prepare($id_record));
$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero'];
$idconto = $info['idconto'];
$idanagrafica = $info['idanagrafica'];
// Preventivo
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_ordine", "required": 1, "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d/%m/%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>';
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_documento", "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
</div>
<div class="alert alert-info" id="box-loading">
<i class="fa fa-spinner fa-spin"></i> '.tr('Caricamento in corso').'...
</div>';
$file = basename(__FILE__);
echo '
<div class="row">
<div id="righeordine" class="col-md-12"></div>
</div>';
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';
?>
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
$('#id_ordine').change( function(){
$('#righeordine').html('<i>Caricamento in corso...</i>');
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
$("#id_documento").on("change", function(){
loader.show();
box.hide();
$('#righeordine').load(globals.rootdir + '/modules/fatture/crea_documento.php?id_module=' + <?php echo Modules::get($module_origin)['id']; ?> + '&id_record=' + $(this).find('option:selected').val() + '&documento=ddt&op=add_ordine&iddocumento=' + globals.id_record);
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
loader.hide();
});
});
</script>
</script>';

View File

@ -2,9 +2,7 @@
include_once __DIR__.'/../../core.php';
if (!in_array($record['stato'], ['Bozza', 'Fatturato'])) {
echo '
<a class="btn btn-info" data-href="'.$rootdir.'/modules/fatture/crea_documento.php?id_module='.$id_module.'&id_record='.$id_record.'&documento=fattura" data-toggle="modal" data-title="Crea fattura">
<i class="fa fa-magic"></i> '.tr('Crea fattura').'
</a>';
}
echo '
<a class="btn btn-info '.(in_array($record['stato'], ['Bozza', 'Parzialmente fatturato']) ? '' : 'disabled').'" data-href="'.$structure->fileurl('crea_documento.php').'?id_module='.$id_module.'&id_record='.$id_record.'&documento=fattura" data-toggle="modal" data-title="'.tr('Crea fattura').'">
<i class="fa fa-magic"></i> '.tr('Crea fattura').'
</a>';

View File

@ -0,0 +1,34 @@
<?php
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
$final_module = $module['name'] == 'Ddt di vendita' ? 'Fatture di vendita' : 'Fatture di acquisto';
$dir = $module['name'] == 'Ddt di vendita' ? 'entrata' : 'uscita';
$options = [
'op' => 'add_ddt',
'id_importazione' => 'id_ddt',
'final_module' => $final_module,
'original_module' => $module['name'],
'sql' => [
'table' => 'dt_ddt',
'rows' => 'dt_righe_ddt',
'id_rows' => 'idddt',
],
'serials' => [
'id_riga' => 'id_riga_ddt',
'condition' => '(id_riga_documento IS NOT NULL)',
],
'button' => tr('Aggiungi'),
'dir' => $dir,
'create_document' => true,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);

View File

@ -2,8 +2,10 @@
include_once __DIR__.'/../../core.php';
use Modules\DDT\DDT;
if (isset($id_record)) {
$ddt = Modules\DDT\DDT::with('tipo', 'stato')->find($id_record);
$ddt = DDT::with('tipo', 'stato')->find($id_record);
$record = $dbo->fetchOne('SELECT *, dt_ddt.note, dt_ddt.idpagamento, dt_ddt.id AS idddt, dt_statiddt.descrizione AS `stato`, dt_tipiddt.descrizione AS `descrizione_tipodoc`,
(SELECT completato FROM dt_statiddt WHERE dt_statiddt.id=dt_ddt.idstatoddt) AS flag_completato

View File

@ -11,6 +11,7 @@ class Articolo extends Article
use RelationTrait;
protected $table = 'dt_righe_ddt';
protected $serialRowID = 'ddt';
/**
* Crea un nuovo articolo collegato ad una ddt.

File diff suppressed because it is too large Load Diff

View File

@ -4,93 +4,82 @@ include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
if ($module['name'] == 'Fatture di vendita') {
$dir = 'entrata';
$conti = 'conti-vendite';
} else {
$dir = 'uscita';
$conti = 'conti-acquisti';
$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita';
if (get('op')) {
$options = [
'op' => 'add_contratto',
'id_importazione' => 'id_contratto',
'final_module' => $module['name'],
'original_module' => 'Contratti',
'sql' => [
'table' => 'co_contratti',
'rows' => 'co_righe_contratti',
'id_rows' => 'idcontratto',
],
'serials' => false,
'button' => tr('Aggiungi'),
'dir' => $dir,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
return;
}
$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record));
$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero'];
$idconto = $info['idconto'];
$idanagrafica = $info['idanagrafica'];
/*
Form di inserimento riga documento
*/
echo '
<p>'.tr('Documento numero _NUM_', [
'_NUM_' => $numero,
]).'</p>
<form action="'.$rootdir.'/editor.php?id_module='.$id_module.'&id_record='.$id_record.'" method="post">
<input type="hidden" name="op" value="addcontratto">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="dir" value="'.$dir.'">';
// Contratto
$_SESSION['superselect']['stato'] = 'fatturabile';
$_SESSION['superselect']['non_fatturato'] = 1;
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Contratto').'", "name": "idcontratto", "required": 1, "ajax-source": "contratti", "extra": "onchange=\"$data = $(this).selectData(); $(\'#descrizione\').val($data.text); $(\'#prezzo\').val($data.totale); $(\'#sconto\').val($data.sconto); if ($data.n_righe>0) { $(\'#import\').prop(\'checked\', true); $(\'input[name=import]\').val(\'1\'); $(\'#import\').removeAttr(\'disabled\'); }else{ $(\'#import\').prop(\'checked\', false); $(\'input[name=import]\').val(\'0\'); $(\'#import\').prop(\'disabled\', true); } \"" ]}
</div>
<div class="col-md-6">
{[ "type": "checkbox", "label": "'.tr('Importa righe').'", "name": "import", "value": "1", "placeholder": "'.tr('Replica righe del contratto in fattura').'" ]}
</div>
</div>';
// Descrizione
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "'.tr('Descrizione').'", "name": "descrizione", "required": 1 ]}
</div>
</div>';
// Leggo l'iva predefinita dall'articolo e se non c'è leggo quella predefinita generica
$idiva = $idiva ?: setting('Iva predefinita');
// Iva
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Iva').'", "name": "idiva", "required": 1, "value": "'.$idiva.'", "ajax-source": "iva" ]}
</div>';
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$idconto.'", "ajax-source": "'.$conti.'" ]}
</div>
</div>';
// Costo unitario
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "number", "label": "'.tr('Costo unitario').'", "name": "prezzo", "required": 1, "icon-after": "&euro;" ]}
</div>';
// Sconto unitario
echo '
<div class="col-md-6">
{[ "type": "number", "label": "'.tr('Sconto unitario').'", "name": "sconto", "icon-after": "choice|untprc" ]}
</div>
</div>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary pull-right"><i class="fa fa-plus"></i> '.tr('Aggiungi').'</button>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Contratto').'", "name": "id_documento", "ajax-source": "contratti" ]}
</div>
</form>';
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
</div>
<div class="alert alert-info" id="box-loading">
<i class="fa fa-spinner fa-spin"></i> '.tr('Caricamento in corso').'...
</div>';
$file = basename(__FILE__);
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
$("#id_documento").on("change", function(){
loader.show();
box.hide();
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
loader.hide();
});
});
</script>';

View File

@ -4,40 +4,88 @@ include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
if ($module['name'] == 'Fatture di vendita') {
$dir = 'entrata';
$module_origin = 'Ddt di vendita';
} else {
$dir = 'uscita';
$module_origin = 'Ddt di acquisto';
$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita';
if (get('op')) {
$options = [
'op' => 'add_ddt',
'id_importazione' => 'id_ddt',
'final_module' => $module['name'],
'original_module' => $module['name'] == 'Fatture di vendita' ? 'Ddt di vendita' : 'Ddt di acquisto',
'sql' => [
'table' => 'dt_ddt',
'rows' => 'dt_righe_ddt',
'id_rows' => 'idddt',
],
'serials' => [
'id_riga' => 'id_riga_ddt',
'condition' => '(id_riga_documento IS NOT NULL)',
],
'button' => tr('Aggiungi'),
'dir' => $dir,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
return;
}
$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record));
$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero'];
$idanagrafica = $info['idanagrafica'];
// Ddt
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Ddt').'", "name": "id_ddt", "required": 1, "values": "query=SELECT dt_ddt.id, CONCAT(\'nr. \', IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM dt_ddt WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoddt IN (SELECT id FROM dt_statiddt WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoddt=(SELECT id FROM dt_tipiddt WHERE dir='.prepare($dir).') AND dt_ddt.id IN (SELECT idddt FROM dt_righe_ddt WHERE dt_righe_ddt.idddt = dt_ddt.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>';
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Ddt').'", "name": "id_documento", "values": "query=SELECT dt_ddt.id, CONCAT(\'DDT num. \', IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM dt_ddt WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoddt IN (SELECT id FROM dt_statiddt WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoddt=(SELECT id FROM dt_tipiddt WHERE dir='.prepare($dir).') AND dt_ddt.id IN (SELECT idddt FROM dt_righe_ddt WHERE dt_righe_ddt.idddt = dt_ddt.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
</div>
<div class="alert alert-info" id="box-loading">
<i class="fa fa-spinner fa-spin"></i> '.tr('Caricamento in corso').'...
</div>';
$file = basename(__FILE__);
echo '
<div class="row">
<div id="righeddt" class="col-md-12"></div>
</div>';
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';
?>
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
$('#id_ddt').change( function(){
$('#righeddt').html('<i>Caricamento in corso...</i>');
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
$("#id_documento").on("change", function(){
loader.show();
box.hide();
$('#righeddt').load(globals.rootdir + '/modules/fatture/crea_documento.php?id_module=' + <?php echo Modules::get($module_origin)['id']; ?> + '&id_record=' + $(this).find('option:selected').val() + '&documento=fattura&op=add_ddt&iddocumento=' + globals.id_record);
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
loader.hide();
});
});
</script>
</script>';

View File

@ -46,7 +46,7 @@ $rs = $dbo->fetchArray('SELECT
AND in_interventi.id_preventivo IS NULL
AND NOT in_interventi.id IN (SELECT idintervento FROM co_promemoria WHERE idintervento IS NOT NULL)');
foreach ($rs as $key => $value) {
$rs[$key]['prezzo'] = get_costi_intervento($value['id'])['totale'];
$rs[$key]['prezzo'] = Translator::numberToLocale(get_costi_intervento($value['id'])['totale']);
}
// Intervento

View File

@ -4,40 +4,88 @@ include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
if ($module['name'] == 'Fatture di vendita') {
$dir = 'entrata';
$module_origin = 'Ordini cliente';
} else {
$dir = 'uscita';
$module_origin = 'Ordini fornitore';
$dir = ($module['name'] == 'Fatture di vendita') ? 'entrata' : 'uscita';
if (get('op')) {
$options = [
'op' => 'add_ordine',
'id_importazione' => 'id_ordine',
'final_module' => $module['name'],
'original_module' => $module['name'] == 'Fatture di vendita' ? 'Ordini cliente' : 'Ordini fornitore',
'sql' => [
'table' => 'or_ordini',
'rows' => 'or_righe_ordini',
'id_rows' => 'idordine',
],
'serials' => [
'id_riga' => 'id_riga_ddt',
'condition' => '(id_riga_documento IS NOT NULL)',
],
'button' => tr('Aggiungi'),
'dir' => $dir,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
return;
}
$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record));
$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero'];
$idanagrafica = $info['idanagrafica'];
// Ordine
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_ordine", "required": 1, "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>';
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Ordine').'", "name": "id_documento", "values": "query=SELECT or_ordini.id, CONCAT(IF(numero_esterno != \'\', numero_esterno, numero), \' del \', DATE_FORMAT(data, \'%d-%m-%Y\')) AS descrizione FROM or_ordini WHERE idanagrafica='.prepare($idanagrafica).' AND idstatoordine IN (SELECT id FROM or_statiordine WHERE descrizione IN(\'Bozza\', \'Evaso\', \'Parzialmente evaso\', \'Parzialmente fatturato\')) AND idtipoordine=(SELECT id FROM or_tipiordine WHERE dir='.prepare($dir).' LIMIT 0,1) AND or_ordini.id IN (SELECT idordine FROM or_righe_ordini WHERE or_righe_ordini.idordine = or_ordini.id AND (qta - qta_evasa) > 0) ORDER BY data DESC, numero DESC" ]}
</div>
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
</div>
<div class="alert alert-info" id="box-loading">
<i class="fa fa-spinner fa-spin"></i> '.tr('Caricamento in corso').'...
</div>';
$file = basename(__FILE__);
echo '
<div class="row">
<div id="righeordine" class="col-md-12"></div>
</div>';
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';
?>
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
$('#id_ordine').change( function(){
$('#righeordine').html('<i>Caricamento in corso...</i>');
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
$("#id_documento").on("change", function(){
loader.show();
box.hide();
$('#righeordine').load(globals.rootdir + '/modules/fatture/crea_documento.php?id_module=' + <?php echo Modules::get($module_origin)['id']; ?> + '&id_record=' + $(this).find('option:selected').val() + '&documento=fattura&op=add_ordine&iddocumento=' + globals.id_record);
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
loader.hide();
});
});
</script>
</script>';

View File

@ -4,93 +4,80 @@ include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
if ($module['name'] == 'Fatture di vendita') {
$dir = 'entrata';
$conti = 'conti-vendite';
} else {
$dir = 'uscita';
$conti = 'conti-acquisti';
if (get('op')) {
$options = [
'op' => 'add_preventivo',
'id_importazione' => 'id_preventivo',
'final_module' => $module['name'],
'original_module' => 'Preventivi',
'sql' => [
'table' => 'co_preventivi',
'rows' => 'co_righe_preventivi',
'id_rows' => 'idpreventivo',
],
'serials' => false,
'button' => tr('Aggiungi'),
'dir' => $dir,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);
return;
}
$info = $dbo->fetchOne('SELECT * FROM co_documenti WHERE id='.prepare($id_record));
$numero = ($info['numero_esterno'] != '') ? $info['numero_esterno'] : $info['numero'];
$idanagrafica = $info['idanagrafica'];
$idconto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto');
/*
Form di inserimento riga documento
*/
echo '
<p>'.tr('Documento numero _NUM_', [
'_NUM_' => $numero,
]).'</p>
<form action="'.$rootdir.'/editor.php?id_module='.$id_module.'&id_record='.$id_record.'" method="post">
<input type="hidden" name="op" value="addpreventivo">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="dir" value="'.$dir.'">';
// Preventivo
$_SESSION['superselect']['stati'] = [
'Accettato',
'In lavorazione',
'In attesa di conferma',
];
$_SESSION['superselect']['non_fatturato'] = 1;
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Preventivo').'", "name": "idpreventivo", "required": 1, "ajax-source": "preventivi", "extra": "onchange=\"$data = $(this).selectData(); $(\'#descrizione\').val($data.text); $(\'#prezzo\').val($data.totale - $data.sconto);console.log($data.totale)\"" ]}
</div>
<div class="col-md-6">
{[ "type": "checkbox", "label": "'.tr('Importa righe').'", "name": "import", "value": "1", "placeholder": "'.tr('Replica righe del preventivo in fattura').'" ]}
</div>
</div>';
// Descrizione
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "'.tr('Descrizione').'", "name": "descrizione", "required": 1 ]}
</div>
</div>';
// Leggo l'iva predefinita dall'articolo e se non c'è leggo quella predefinita generica
$idiva = $idiva ?: setting('Iva predefinita');
// Iva
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Iva').'", "name": "idiva", "required": 1, "value": "'.$idiva.'", "ajax-source": "iva" ]}
</div>';
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Conto').'", "name": "idconto", "required": 1, "value": "'.$idconto.'", "ajax-source": "'.$conti.'" ]}
</div>
</div>';
// Costo unitario
echo '
<div class="row">
<div class="col-md-12">
{[ "type": "number", "label": "'.tr('Costo unitario').'", "name": "prezzo", "required": 1, "icon-after": "&euro;", "disabled": 1 ]}
</div>
</div>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" class="btn btn-primary pull-right"><i class="fa fa-plus"></i> '.tr('Aggiungi').'</button>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "select", "label": "'.tr('Preventivo').'", "name": "id_documento", "ajax-source": "preventivi" ]}
</div>
</form>';
</div>
<div class="box" id="info-box">
<div class="box-header with-border">
<h3 class="box-title">'.tr('Informazioni di importazione').'</h3>
</div>
<div class="box-body" id="righe_documento">
</div>
</div>
<div class="alert alert-info" id="box-loading">
<i class="fa fa-spinner fa-spin"></i> '.tr('Caricamento in corso').'...
</div>';
$file = basename(__FILE__);
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';
<script src="'.$rootdir.'/lib/init.js"></script>
<script>
var box = $("#info-box");
var content = $("#righe_documento");
var loader = $("#box-loading");
$(document).ready(function(){
box.hide();
loader.hide();
})
$("#id_documento").on("change", function(){
loader.show();
box.hide();
var id = $(this).selectData() ? $(this).selectData().id : "";
content.html("<i>'.tr('Caricamento in corso').'...</i>");
content.load("'.$structure->fileurl($file).'?id_module='.$id_module.'&id_record=" + id + "&documento=fattura&op=add_ordine&iddocumento='.$id_record.'", function() {
if(content.html() != ""){
box.show();
}
loader.hide();
});
});
</script>';

View File

@ -13,10 +13,10 @@ echo '
<i class="fa fa-copy"></i> '.tr('Duplica fattura').'
</button>';
if ($dir == 'entrata' && empty($record['ref_documento']) && $record['stato'] == 'Emessa') {
if ($dir == 'entrata') {
echo '
<div class="btn-group">
<button type="button" class="btn btn-primary unblockable dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<button type="button" class="btn btn-primary unblockable dropdown-toggle '.(!empty($record['ref_documento']) || $record['stato'] == 'Emessa' ? '' : 'disabled').'" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<i class="fa fa-magic"></i> '.tr('Crea').' <span class="caret"></span>
<span class="sr-only">Toggle Dropdown</span>
</button>
@ -41,3 +41,30 @@ if (empty($record['is_fiscale'])) {
<i class="fa fa-upload"></i> '.tr('Trasforma in fattura fiscale').'
</button>';
}
?>
<?php
if (!empty($record['is_fiscale'])) {
// Aggiunta prima nota solo se non c'è già, se non si è in bozza o se il pagamento non è completo
$n2 = $dbo->fetchNum('SELECT id FROM co_movimenti WHERE iddocumento='.prepare($id_record).' AND primanota=1');
$rs3 = $dbo->fetchArray('SELECT SUM(da_pagare-pagato) AS differenza, SUM(da_pagare) FROM co_scadenziario GROUP BY iddocumento HAVING iddocumento='.prepare($id_record));
$differenza = isset($rs3[0]) ? $rs3[0]['differenza'] : null;
$da_pagare = isset($rs3[0]) ? $rs3[0]['da_pagare'] : null;
if (($n2 <= 0 && $record['stato'] == 'Emessa') || $differenza != 0) {
?>
<button type="button" class="btn btn-primary <?php echo (!empty(Modules::get('Prima nota'))) ? '' : 'disabled'; ?>" onclick="launch_modal( '<?php echo tr('Aggiungi prima nota'); ?>', '<?php echo $rootdir; ?>/add.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>&iddocumento=<?php echo $id_record; ?>&dir=<?php echo $dir; ?>', 1 );"><small><i class="fa fa-euro"></i> <?php echo tr('Registrazione contabile pagamento'); ?>...</small></button>
<?php
}
if ($record['stato'] == 'Pagato') {
?>
<button type="button" class="btn btn-primary tip" onclick="if( confirm('<?php echo tr('Se riapri questa fattura verrà azzerato lo scadenzario e la prima nota. Continuare?'); ?>') ){ $.post( '<?php echo $rootdir; ?>/editor.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>', { id_module: '<?php echo $id_module; ?>', id_record: '<?php echo $id_record; ?>', op: 'reopen' }, function(){ location.href='<?php echo $rootdir; ?>/editor.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>'; } ); }" title="<?php echo tr('Riporta la fattura in stato bozza e ne elimina i movimenti contabili.'); ?>" ><i class="fa fa-folder-open"></i> <?php echo tr('Riapri fattura'); ?>...</button>
<?php
}
}
?>

View File

@ -4,340 +4,29 @@ include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
$data = [
'ddt' => [
'table' => 'dt_ddt', // Tabella del documento
'rows' => 'dt_righe_ddt', // Tabella delle righe
'id' => 'idddt', // ID nella tabella delle righe
'condition' => '(id_riga_documento IS NOT NULL)', // Condizione per i seriali
],
'ord' => [
'table' => 'or_ordini',
'rows' => 'or_righe_ordini',
'id' => 'idordine',
'condition' => '(id_riga_ddt IS NOT NULL OR id_riga_documento IS NOT NULL)',
],
'fat' => [
$options = [
'op' => 'nota_credito',
'id_importazione' => 'id_documento',
'final_module' => $module['name'],
'original_module' => $module['name'],
'sql' => [
'table' => 'co_documenti',
'rows' => 'co_righe_documenti',
'id' => 'iddocumento',
'condition' => '(1 = 2)',
'allow-empty' => true,
'id_rows' => 'iddocumento',
],
'serials' => [
'id_riga' => 'id_riga_documento',
'condition' => '(1 = 2)',
],
'button' => tr('Aggiungi'),
'dir' => $dir,
'create_document' => true,
'allow-empty' => true,
];
$documento = get('documento');
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
if ($module['name'] == 'Ordini cliente' || $module['name'] == 'Ordini fornitore') {
$pos = 'ord';
$op = ($documento == 'ddt') ? 'ddt_da_ordine' : 'fattura_da_ordine';
$head = tr('Ordine numero _NUM_');
$dir = ($module['name'] == 'Ordini cliente') ? 'entrata' : 'uscita';
} elseif ($module['name'] == 'Ddt di vendita' || $module['name'] == 'Ddt di acquisto') {
$pos = 'ddt';
$op = 'fattura_da_ddt';
$head = tr('Ddt numero _NUM_');
$dir = ($module['name'] == 'Ddt di vendita') ? 'entrata' : 'uscita';
} else {
$pos = 'fat';
$op = 'nota_credito';
$head = tr('Fattura numero _NUM_');
$dir = 'entrata';
}
$table = $data[$pos]['table'];
$rows = $data[$pos]['rows'];
$id = $data[$pos]['id'];
$row = str_replace('id', 'id_riga_', $id);
if ($module['name'] == 'Ordini cliente') {
$module_name = ($documento == 'ddt') ? 'Ddt di vendita' : 'Fatture di vendita';
} elseif ($module['name'] == 'Ordini fornitore') {
$module_name = ($documento == 'ddt') ? 'Ddt di acquisto' : 'Fatture di acquisto';
} elseif ($module['name'] == 'Ddt di acquisto') {
$module_name = 'Fatture di acquisto';
} else {
$module_name = 'Fatture di vendita';
}
$op = !empty(get('op')) ? get('op') : $op;
$button = ($documento == 'ddt') ? tr('Crea ddt') : tr('Crea fattura');
$button = !empty(get('op')) ? tr('Aggiungi') : $button;
// Info documento
$rs = $dbo->fetchArray('SELECT * FROM '.$table.' WHERE id='.prepare($id_record));
$numero = !empty($rs[0]['numero_esterno']) ? $rs[0]['numero_esterno'] : $rs[0]['numero'];
$idanagrafica = $rs[0]['idanagrafica'];
$idpagamento = $rs[0]['idpagamento'];
$idconto = $rs[0]['idconto'];
if (empty($idconto)) {
$idconto = ($dir == 'entrata') ? setting('Conto predefinito fatture di vendita') : setting('Conto predefinito fatture di acquisto');
}
/*
Form di inserimento riga documento
*/
echo '
<p>'.str_replace('_NUM_', $numero, $head).'.</p>';
// Selezione articoli dell'ordine da portare nel ddt
$rs = $dbo->fetchArray('SELECT *, IFNULL((SELECT codice FROM mg_articoli WHERE id=idarticolo),"") AS codice, (qta - qta_evasa) AS qta_rimanente FROM '.$table.' INNER JOIN '.$rows.' ON '.$table.'.id='.$rows.'.'.$id.' WHERE '.$table.'.id='.prepare($id_record).' HAVING qta_rimanente > 0 OR is_descrizione = 1 ORDER BY `order`');
if (!empty($rs)) {
echo '
<p>'.tr('Seleziona le righe e le relative quantità da inserire nel documento').'.</p>
<form action="'.$rootdir.'/editor.php?id_module='.Modules::get($module_name)['id'].(!empty(get('iddocumento')) ? '&id_record='.get('iddocumento') : '').'" method="post">
<input type="hidden" name="'.$id.'" value="'.$id_record.'">
<input type="hidden" name="idanagrafica" value="'.$idanagrafica.'">
<input type="hidden" name="idconto" value="'.$idconto.'">
<input type="hidden" name="idpagamento" value="'.$idpagamento.'">
<input type="hidden" name="iddocumento" value="'.$id_record.'">
<input type="hidden" name="op" value="'.$op.'">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="dir" value="'.$dir.'">';
if (empty(get('op'))) {
echo '
<div class="row">
<div class="col-md-6">
{[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]}
</div>';
if ($module_name == 'Fatture di vendita' || $module_name == 'Fatture di acquisto') {
$rs_segment = $dbo->fetchArray("SELECT * FROM zz_segments WHERE predefined_accredito='1'");
if ($op == 'nota_accredito' && sizeof($rs_segment) > 0) {
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare(Modules::get($module_name)['id']).' ORDER BY name", "value": "'.$rs_segment[0]['id'].'" ]}
</div>';
} else {
echo '
<div class="col-md-6">
{[ "type": "select", "label": "'.tr('Sezionale').'", "name": "id_segment", "required": 1, "values": "query=SELECT id, name AS descrizione FROM zz_segments WHERE id_module='.prepare(Modules::get($module_name)['id']).' ORDER BY name", "value": "'.$_SESSION['module_'.Modules::get($module_name)['id']]['id_segment'].'" ]}
</div>';
}
}
echo
'</div>';
}
echo '
<div class="clearfix"></div>
<br>
<table class="table table-striped table-hover table-condensed">
<tr>
<th>'.tr('Descrizione').'</th>
<th width="10%">'.tr('Q.').'</th>
<th width="15%">'.tr('Q. da evadere').'</th>
<th width="20%">'.tr('Subtot.').'</th>
<th width="20%">'.tr('Seriali').'</th>
</tr>';
$totale = 0.00;
foreach ($rs as $i => $r) {
// Descrizione
echo '
<tr>
<td>
<input type="hidden" name="abilita_serial['.$r['id'].']" value="'.$r['abilita_serial'].'" />
<input type="hidden" id="idarticolo_'.$i.'" name="idarticolo['.$r['id'].']" value="'.$r['idarticolo'].'" />
<input type="hidden" id="descrizione_'.$i.'" name="descrizione['.$r['id'].']" value="'.$r['descrizione'].'" />';
// Checkbox - da evadere?
echo '
<input type="checkbox" checked="checked" id="checked_'.$i.'" name="evadere['.$r['id'].']" value="on" onclick="ricalcola_subtotale_riga('.$i.');" />';
$descrizione = (!empty($r['codice']) ? $r['codice'].' - ' : '').$r['descrizione'];
echo '&nbsp;'.nl2br($descrizione);
echo '
</td>';
// Q.tà rimanente
echo '
<td>
<input type="hidden" id="qtamax_'.$i.'" value="'.($r['qta'] - $r['qta_evasa']).'" />
<input type="hidden" id="um_'.$i.'" name="um['.$r['id'].']" value="'.$r['um'].'" />
<p class="text-center">'.Translator::numberToLocale($r['qta_rimanente']).'</p>
</td>';
// Q.tà da evadere
echo '
<td>
{[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta_rimanente'].'", "extra" : "onkeyup=\"ricalcola_subtotale_riga('.$i.');\"", "decimals": "qta", "min-value": "0", "extra": "'.(($r['is_descrizione']) ? 'readonly' : '').'" ]}
</td>';
// Subtotale
$subtotale = $r['subtotale'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
$sconto = $r['sconto'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
$iva = $r['iva'] / $r['qta'] * ($r['qta'] - $r['qta_evasa']);
echo '
<td>
<input type="hidden" id="subtot_'.$i.'" name="subtot['.$r['id'].']" value="'.str_replace('.', ',', ($r['subtotale'] / $r['qta'])).'" />
<input type="hidden" id="sconto_'.$i.'" name="sconto['.$r['id'].']" value="'.str_replace('.', ',', ($r['sconto'] / $r['qta'])).'" />
<input type="hidden" id="idiva_'.$i.'" name="idiva['.$r['id'].']" value="'.$r['idiva'].'" />
<input type="hidden" id="iva_'.$i.'" name="iva['.$r['id'].']" value="'.str_replace('.', ',', ($r['iva'] / $r['qta'])).'" />
<big id="subtotale_'.$i.'">'.Translator::numberToLocale($subtotale - $sconto + $iva).' &euro;</big><br/>
<small style="color:#777;" id="subtotaledettagli_'.$i.'">'.Translator::numberToLocale($subtotale - $sconto).' + '.Translator::numberToLocale($iva).'</small>
</td>';
// Seriali
echo '
<td>';
if (!empty($r['abilita_serial'])) {
$query = 'SELECT DISTINCT serial AS id, serial AS descrizione FROM mg_prodotti WHERE dir='.prepare($dir).' AND '.$row.' = '.prepare($r['id']).' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti AS t WHERE serial IS NOT NULL AND dir='.prepare($dir).' AND '.$data[$pos]['condition'].')';
$values = $dbo->fetchArray($query);
if (!empty($values)) {
echo '
{[ "type": "select", "name": "serial['.$r['id'].'][]", "id": "serial_'.$i.'", "multiple": 1, "values": "query='.$query.'", "value": "'.implode(',', array_column($values, 'id')).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]}';
} else {
echo '-';
}
} else {
echo '-';
}
echo '
</td>
</tr>';
$totale += $subtotale - $sconto + $iva;
}
// Totale
echo '
<tr>
<td colspan="4" align="right" class="text-right">
<b>'.tr('Totale').':</b>
</td>
<td class="text-right" colspan="2">
<big id="totale">'.Translator::numberToLocale($totale).' &euro;</big>
</td>
</tr>
</table>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" id="submit_btn" class="btn btn-primary pull-right">
<i class="fa fa-plus"></i> '.$button.'
</button>
</div>
</div>
</form>';
} else {
echo '
<p>'.tr('Non ci sono articoli da evadere').'...</p>';
}
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';
?>
<script type="text/javascript">
function ricalcola_subtotale_riga(r) {
subtot = $("#subtot_" + r).val();
sconto = $("#sconto_" + r).val();
iva = $("#iva_" + r).val();
qtamax = $("#qtamax_" + r).val() ? $("#qtamax_" + r).val() : 0;
subtot = parseFloat(subtot);
sconto = parseFloat(sconto);
iva = parseFloat(iva);
qtamax = parseFloat(qtamax);
subtot = subtot - sconto;
qta = $("#qta_" + r).val().toEnglish();
// Se inserisco una quantità da evadere maggiore di quella rimanente, la imposto al massimo possibile
if (qta > qtamax) {
qta = qtamax;
$('#qta_' + r).val(qta);
}
// Se tolgo la spunta della casella dell'evasione devo azzerare i conteggi
if (isNaN(qta) || !$('#checked_' + r).is(':checked')) {
qta = 0;
}
$("#serial_" + r).selectClear();
$("#serial_" + r).select2("destroy");
$("#serial_" + r).data('maximum', qta);
start_superselect();
subtotale = (subtot * qta + iva * qta).toLocale();
$("#subtotale_" + r).html(subtotale + " &euro;");
$("#subtotaledettagli_" + r).html((subtot * qta).toLocale() + " + " + (iva * qta).toLocale());
ricalcola_totale();
}
function ricalcola_totale() {
tot_qta = 0;
r = 0;
totale = 0.00;
$('input[id*=qta_]').each(function() {
qta = $(this).val().toEnglish();
if (!$('#checked_' + r).is(':checked') || isNaN(qta)) {
qta = 0;
}
subtot = $("#subtot_" + r).val();
sconto = $("#sconto_" + r).val();
iva = $("#iva_" + r).val();
subtot = parseFloat(subtot);
sconto = parseFloat(sconto);
iva = parseFloat(iva);
subtot = subtot - sconto;
totale += subtot * qta + iva * qta;
r++;
tot_qta += qta;
});
$('#totale').html((totale.toLocale()) + " &euro;");
<?php
if (empty($data[$pos]['allow-empty'])) {
echo '
if (tot_qta > 0)
$("#submit_btn").show();
else
$("#submit_btn").hide();';
}
?>
}
</script>
echo App::load('importa.php', $result, $options, true);

View File

@ -182,35 +182,6 @@ if (empty($record['is_fiscale'])) {
<div class="col-md-3">
{[ "type": "select", "label": "<?php echo tr('Banca'); ?>", "name": "idbanca", "values": "query=SELECT id, CONCAT (nome, ' - ' , iban) AS descrizione FROM co_banche WHERE deleted_at IS NULL ORDER BY nome ASC", "value": "$idbanca$", "icon-after": "add|<?php echo Modules::get('Banche')['id']; ?>||", "extra": " <?php echo ($record['stato'] == 'Bozza') ? '' : 'disabled'; ?> " ]}
</div>
<div class="col-md-3">
<label>&nbsp;</label><br>
<?php
if (!empty($record['is_fiscale'])) {
// Aggiunta prima nota solo se non c'è già, se non si è in bozza o se il pagamento non è completo
$n2 = $dbo->fetchNum('SELECT id FROM co_movimenti WHERE iddocumento='.prepare($id_record).' AND primanota=1');
$rs3 = $dbo->fetchArray('SELECT SUM(da_pagare-pagato) AS differenza, SUM(da_pagare) FROM co_scadenziario GROUP BY iddocumento HAVING iddocumento='.prepare($id_record));
$differenza = isset($rs3[0]) ? $rs3[0]['differenza'] : null;
$da_pagare = isset($rs3[0]) ? $rs3[0]['da_pagare'] : null;
if (($n2 <= 0 && $record['stato'] == 'Emessa') || $differenza != 0) {
?>
<a class="btn btn-primary btn-block <?php echo (!empty(Modules::get('Prima nota'))) ? '' : 'disabled'; ?>" href="javascript:;" onclick="launch_modal( 'Aggiungi prima nota', '<?php echo $rootdir; ?>/add.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>&iddocumento=<?php echo $id_record; ?>&dir=<?php echo $dir; ?>', 1 );"><i class="fa fa-euro"></i> <?php echo tr('Registrazione contabile pagamento'); ?>...</a><br><br>
<?php
}
if ($record['stato'] == 'Pagato') {
?>
<a class="btn btn-primary btn-block" href="javascript:;" onclick="if( confirm('Se riapri questa fattura verrà azzerato lo scadenzario e la prima nota. Continuare?') ){ $.post( '<?php echo $rootdir; ?>/editor.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>', { id_module: '<?php echo $id_module; ?>', id_record: '<?php echo $id_record; ?>', op: 'reopen' }, function(){ location.href='<?php echo $rootdir; ?>/editor.php?id_module=<?php echo $id_module; ?>&id_record=<?php echo $id_record; ?>'; } ); }" title="Registrazione contabile pagamento"><i class="fa fa-folder-open"></i> <?php echo tr('Riapri fattura'); ?>...</a>
<?php
}
}
?>
</div>
</div>
<?php
@ -232,7 +203,7 @@ if ($dir == 'uscita') {
<div class="row">
<div class="col-md-3">
{[ "type": "number", "label": "<?php echo tr('Sconto incondizionato'); ?>", "name": "sconto_generico", "value": "$sconto_globale$", "help": "<?php echo tr('Sconto complessivo della fattura.'); ?>", "icon-after": "choice|untprc|$tipo_sconto_globale$"<?php echo ($record['stato'] == 'Emessa') ? ', "disabled" : 1' : ''; ?> ]}
{[ "type": "number", "label": "<?php echo tr('Sconto incondizionato'); ?>", "name": "sconto_generico", "value": "$sconto_globale$", "help": "<?php echo tr('Sconto complessivo della fattura. Il valore positivo indica uno sconto. Per applicare un rincaro inserire un valore negativo.'); ?>", "icon-after": "choice|untprc|$tipo_sconto_globale$"<?php echo ($record['stato'] == 'Emessa') ? ', "disabled" : 1' : ''; ?> ]}
</div>
<div class="col-md-3">
@ -250,13 +221,16 @@ if ($dir == 'uscita') {
<?php
}
?>
<div class="col-md-3">
{[ "type": "select", "label": "<?php echo tr('Ritenuta contributi'); ?>", "name": "id_ritenuta_contributi", "value": "$id_ritenuta_contributi$", "values": "query=SELECT * FROM co_ritenuta_contributi" ]}
</div>
</div>
<div class="row">
<div class="col-md-12">
{[ "type": "textarea", "label": "<?php echo tr('Note'); ?>", "name": "note", "help": "<?php echo tr('Note visibili anche in stampa.'); ?>", "value": "$note$" ]}
{[ "type": "textarea", "label": "<?php echo tr('Note'); ?>", "name": "note", "help": "<?php echo tr('Note visibili anche in fattura.'); ?>", "value": "$note$" ]}
</div>
</div>
@ -432,7 +406,7 @@ if ($record['stato'] != 'Pagato' && $record['stato'] != 'Emessa') {
</div>';
// Lettura preventivi accettati, in attesa di conferma o in lavorazione
$prev_query = 'SELECT COUNT(*) AS tot FROM co_preventivi WHERE idanagrafica='.prepare($record['idanagrafica'])." AND id NOT IN (SELECT idpreventivo FROM co_righe_documenti WHERE idpreventivo IS NOT NULL) AND id NOT IN (SELECT idpreventivo FROM or_righe_ordini WHERE NOT idpreventivo IS NOT NULL) AND idstato IN(SELECT id FROM co_statipreventivi WHERE descrizione='Accettato' OR descrizione='In lavorazione' OR descrizione='In attesa di conferma') AND default_revision=1";
$prev_query = 'SELECT COUNT(*) AS tot FROM co_preventivi WHERE idanagrafica='.prepare($record['idanagrafica'])." AND idstato IN(SELECT id FROM co_statipreventivi WHERE descrizione='Accettato' OR descrizione='In lavorazione' OR descrizione='In attesa di conferma') AND default_revision=1 AND co_preventivi.id IN (SELECT idpreventivo FROM co_righe_preventivi WHERE co_righe_preventivi.idpreventivo = co_preventivi.id AND (qta - qta_evasa) > 0)";
$preventivi = $dbo->fetchArray($prev_query)[0]['tot'];
echo '
<div class="tip" data-toggle="tooltip" title="'.tr('Preventivi accettati, in attesa di conferma o in lavorazione.').'" style="display:inline;">
@ -442,7 +416,7 @@ if ($record['stato'] != 'Pagato' && $record['stato'] != 'Emessa') {
</div>';
// Lettura contratti accettati, in attesa di conferma o in lavorazione
$contr_query = 'SELECT COUNT(*) AS tot FROM co_contratti WHERE idanagrafica='.prepare($record['idanagrafica']).' AND id NOT IN (SELECT idcontratto FROM co_righe_documenti WHERE idcontratto IS NOT NULL) AND idstato IN( SELECT id FROM co_staticontratti WHERE fatturabile = 1) AND NOT EXISTS (SELECT id FROM co_righe_documenti WHERE co_righe_documenti.idcontratto = co_contratti.id)';
$contr_query = 'SELECT COUNT(*) AS tot FROM co_contratti WHERE idanagrafica='.prepare($record['idanagrafica']).' AND idstato IN( SELECT id FROM co_staticontratti WHERE fatturabile = 1) AND co_contratti.id IN (SELECT idcontratto FROM co_righe_contratti WHERE co_righe_contratti.idcontratto = co_contratti.id AND (qta - qta_evasa) > 0)';
$contratti = $dbo->fetchArray($contr_query)[0]['tot'];
echo '
<div class="tip" data-toggle="tooltip" title="'.tr('Contratti accettati, in attesa di conferma o in lavorazione.').'" style="display:inline;">
@ -527,7 +501,7 @@ include $docroot.'/modules/fatture/row-list.php';
<?php
if ($dir == 'entrata') {
echo '
<div class="alert alert-info text-center">'.tr('Per allegare un documento alla fattura elettronica caricare il file specificando come categoria "Fattura Elettronica"').'.</div>';
<div class="alert alert-info text-center">'.tr('Per allegare un documento alla fattura elettronica caricare il file PDF specificando come categoria "Fattura Elettronica"').'.</div>';
}
?>

View File

@ -111,9 +111,8 @@ function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = 0)
$fattura = Fattura::find($iddocumento);
$ricalcola = true;
if ($fattura->isFE()) {
$ricalcola = $fattura->registraScadenzeFE($pagato);
$scadenze_fe = $fattura->registraScadenzeFE($pagato);
}
// Lettura data di emissione fattura
@ -122,7 +121,7 @@ function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = 0)
$data = $rs[0]['data'];
$ritenutaacconto = $rs[0]['ritenutaacconto'];
if ($ricalcola) {
if (empty($scadenze_fe)) {
$totale_da_pagare = 0.00;
$totale_fattura = get_totale_fattura($iddocumento);
@ -198,9 +197,9 @@ function aggiungi_scadenza($iddocumento, $pagamento = '', $pagato = 0)
if ($pagato) {
$id_scadenza = $dbo->lastInsertedID();
$dbo->update('co_scadenziario', [
'pagato' => $da_pagare,
'data_pagamento' => $data,
], ['id' => $id_scadenza]);
'pagato' => $da_pagare,
'data_pagamento' => $data,
], ['id' => $id_scadenza]);
}
}
}
@ -394,7 +393,17 @@ function aggiungi_movimento($iddocumento, $dir, $primanota = 0)
$numero = $rs[0]['numero'];
}
$descrizione = $rs[0]['descrizione_tipodoc']." numero $numero";
// Abbreviazioni contabili dei movimenti
$tipodoc = '';
if ($rs[0]['descrizione_tipodoc'] == 'Nota di credito') {
$tipodoc = 'Nota di credito';
} elseif ($rs[0]['descrizione_tipodoc'] == 'Nota di debito') {
$tipodoc = 'Nota di debito';
} else {
$tipodoc = 'Fattura';
}
$descrizione = $tipodoc.' num. '.$numero;
/*
Il mastrino si apre con almeno 3 righe di solito (esempio fattura di vendita):

View File

@ -3,7 +3,7 @@
include_once __DIR__.'/../../core.php';
// Info documento
$rs = $dbo->fetchArray('SELECT idanagrafica FROM co_documenti WHERE id='.prepare($id_record));
$rs = $dbo->fetchArray('SELECT * FROM co_documenti WHERE id='.prepare($id_record));
$idanagrafica = $rs[0]['idanagrafica'];
if ($module['name'] == 'Fatture di vendita') {
@ -26,6 +26,7 @@ $options = [
'dir' => $dir,
'conti' => $conti,
'idanagrafica' => $idanagrafica,
'show-ritenuta-contributi' => !empty($rs[0]['id_ritenuta_contributi']),
];
// Dati di default
@ -38,6 +39,7 @@ $result = [
'tipo_sconto' => '',
'idiva' => '',
'idconto' => $idconto,
'ritenuta_contributi' => true,
];
// Leggo l'iva predefinita per l'anagrafica e se non c'è leggo quella predefinita generica
@ -53,8 +55,13 @@ if ($listino[0]['prc_guadagno'] > 0) {
}
// Leggo la ritenuta d'acconto predefinita per l'anagrafica e se non c'è leggo quella predefinita generica
// id_ritenuta_acconto_vendite oppure id_ritenuta_acconto_acquisti
$ritenuta_acconto = $dbo->fetchOne('SELECT id_ritenuta_acconto_'.($dir == 'uscita' ? 'acquisti' : 'vendite').' AS id_ritenuta_acconto FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica));
$options['id_ritenuta_acconto_predefined'] = $ritenuta_acconto['id_ritenuta_acconto'];
$id_ritenuta_acconto = $ritenuta_acconto['id_ritenuta_acconto'];
if ($dir == 'entrata' && empty($id_ritenuta_acconto)) {
$id_ritenuta_acconto = setting("Percentuale ritenuta d'acconto");
}
$options['id_ritenuta_acconto_predefined'] = $id_ritenuta_acconto;
// Importazione della gestione dedicata
$file = 'riga';

View File

@ -22,6 +22,7 @@ $options = [
'conti' => $conti,
'idanagrafica' => $idanagrafica,
'edit_articolo' => false,
'show-ritenuta-contributi' => !empty($rs[0]['id_ritenuta_contributi']),
];
// Dati della riga

View File

@ -47,7 +47,7 @@ foreach ($righe as $row) {
$ref_modulo = Modules::get('Articoli')['id'];
$ref_id = $riga['idarticolo'];
$riga['descrizione'] = (!empty($rowarticolo) ? $rowarticolo->codice.' - ' : '').$riga['descrizione'];
$riga['descrizione'] = (!empty($row->articolo) ? $row->articolo->codice.' - ' : '').$riga['descrizione'];
$delete = 'unlink_articolo';
@ -100,7 +100,7 @@ foreach ($righe as $row) {
// Individuazione dei seriali
if (!empty($riga['abilita_serial'])) {
$serials = $rowserials;
$serials = $row->serials;
$mancanti = $riga['qta'] - count($serials);
if ($mancanti > 0) {
@ -200,7 +200,7 @@ foreach ($righe as $row) {
</small>';
}
if ($rowsconto_unitario > 0) {
if ($row->sconto_unitario > 0) {
echo '
<br><small class="label label-danger">'.tr('sconto _TOT_ _TYPE_', [
'_TOT_' => Translator::numberToLocale($row->sconto_unitario),
@ -232,7 +232,7 @@ foreach ($righe as $row) {
echo '
'.Translator::numberToLocale($riga['imponibile_scontato']).' &euro;';
/*
<br><small class="text-'.($rowguadagno > 0 ? 'success' : 'danger').'">
<br><small class="text-'.($row->guadagno > 0 ? 'success' : 'danger').'">
'.tr('Guadagno').': '.Translator::numberToLocale($row->guadagno).' &euro;
</small>';
*/
@ -426,6 +426,20 @@ if (!empty($fattura->ritenuta_acconto)) {
</tr>';
}
// RITENUTA CONTRIBUTI
if (!empty($fattura->totale_ritenuta_contributi)) {
echo '
<tr>
<td colspan="5" class="text-right">
<b>'.tr('Ritenuta contributi', [], ['upper' => true]).':</b>
</td>
<td align="right">
'.Translator::numberToLocale($fattura->totale_ritenuta_contributi).' &euro;
</td>
<td></td>
</tr>';
}
// NETTO A PAGARE
if ($totale != $netto_a_pagare) {
echo '

View File

@ -11,6 +11,7 @@ class Articolo extends Article
use RelationTrait;
protected $table = 'co_righe_documenti';
protected $serialRowID = 'documento';
/**
* Crea un nuovo articolo collegato ad una fattura.

View File

@ -3,6 +3,8 @@
namespace Modules\Fatture\Components;
use Modules\Fatture\Fattura;
use Modules\Ritenute\RitenutaAcconto;
use Modules\Rivalse\RivalsaINPS;
trait RelationTrait
{
@ -23,7 +25,7 @@ trait RelationTrait
public function getNettoAttribute()
{
$result = $this->totale - $this->ritenuta_acconto;
$result = $this->totale - $this->ritenuta_acconto - $this->ritenuta_contributi;
if ($this->parent->split_payment) {
$result = $result - $this->iva;
@ -31,4 +33,122 @@ trait RelationTrait
return $result;
}
/**
* Restituisce il totale (imponibile + iva + rivalsa_inps + iva_rivalsainps) dell'elemento.
*
* @return float
*/
public function getTotaleAttribute()
{
return $this->imponibile_scontato + $this->iva + $this->rivalsa_inps + $this->iva_rivalsa_inps;
}
public function getRivalsaINPSAttribute()
{
return $this->imponibile_scontato / 100 * $this->rivalsa->percentuale;
}
public function getIvaRivalsaINPSAttribute()
{
return $this->rivalsa_inps / 100 * $this->aliquota->percentuale;
}
public function getRitenutaAccontoAttribute()
{
$result = $this->imponibile_scontato;
if ($this->calcolo_ritenuta_acconto == 'IMP+RIV') {
$result += $this->rivalsainps;
}
return $result / 100 * $this->ritenuta->percentuale;
}
public function getRitenutaContributiAttribute()
{
if ($this->attributes['ritenuta_contributi']) {
$result = $this->imponibile_scontato;
$ritenuta = $this->parent->ritenutaContributi;
$result = $result * $ritenuta->percentuale_imponibile / 100;
return $result / 100 * $ritenuta->percentuale;
}
return 0;
}
/**
* Imposta l'identificatore della Rivalsa INPS.
*
* @param int $value
*/
public function setIdRivalsaINPSAttribute($value)
{
$this->attributes['idrivalsainps'] = $value;
$this->load('rivalsa');
}
/**
* Imposta l'identificatore della Ritenuta d'Acconto.
*
* @param int $value
*/
public function setIdRitenutaAccontoAttribute($value)
{
$this->attributes['idritenutaacconto'] = $value;
$this->load('ritenuta');
}
public function getIdContoAttribute()
{
return $this->idconto;
}
public function setIdContoAttribute($value)
{
$this->attributes['idconto'] = $value;
}
public function rivalsa()
{
return $this->belongsTo(RivalsaINPS::class, 'idrivalsainps');
}
public function ritenuta()
{
return $this->belongsTo(RitenutaAcconto::class, 'idritenutaacconto');
}
/**
* Salva la riga, impostando i campi dipendenti dai parametri singoli.
*
* @param array $options
*
* @return bool
*/
public function save(array $options = [])
{
$this->fixRitenutaAcconto();
$this->fixRivalsaINPS();
return parent::save($options);
}
/**
* Effettua i conti per la Rivalsa INPS.
*/
protected function fixRivalsaINPS()
{
$this->attributes['rivalsainps'] = $this->rivalsa_inps;
}
/**
* Effettua i conti per la Ritenuta d'Acconto, basandosi sul valore del campo calcolo_ritenuta_acconto.
*/
protected function fixRitenutaAcconto()
{
$this->attributes['ritenutaacconto'] = $this->ritenuta_acconto;
}
}

View File

@ -4,6 +4,7 @@ namespace Modules\Fatture;
use Common\Document;
use Modules\Anagrafiche\Anagrafica;
use Modules\RitenuteContributi\RitenutaContributi;
use Plugins\ExportFE\FatturaElettronica;
use Traits\RecordTrait;
use Util\Generator;
@ -87,6 +88,9 @@ class Fattura extends Document
$model->idconto = $id_conto;
$model->idsede = $id_sede;
$id_ritenuta_contributi = ($tipo_documento->dir == 'entrata') ? setting('Ritenuta contributi') : null;
$model->id_ritenuta_contributi = $id_ritenuta_contributi ?: null;
if (!empty($id_pagamento)) {
$model->idpagamento = $id_pagamento;
}
@ -135,6 +139,8 @@ class Fattura extends Document
return $this->tipo->dir == 'entrata' ? 'Fatture di vendita' : 'Fatture di acquisto';
}
// Calcoli
/**
* Calcola il netto a pagare della fattura.
*
@ -142,7 +148,148 @@ class Fattura extends Document
*/
public function getNettoAttribute()
{
return parent::getNettoAttribute() + $this->bollo;
return $this->calcola('netto') + $this->bollo;
}
/**
* Calcola la rivalsa INPS totale della fattura.
*
* @return float
*/
public function getRivalsaINPSAttribute()
{
return $this->calcola('rivalsa_inps');
}
/**
* Calcola l'IVA totale della fattura.
*
* @return float
*/
public function getIvaAttribute()
{
return $this->calcola('iva', 'iva_rivalsa_inps');
}
/**
* Calcola l'iva della rivalsa INPS totale della fattura.
*
* @return float
*/
public function getIvaRivalsaINPSAttribute()
{
return $this->calcola('iva_rivalsa_inps');
}
/**
* Calcola la ritenuta d'acconto totale della fattura.
*
* @return float
*/
public function getRitenutaAccontoAttribute()
{
return $this->calcola('ritenuta_acconto');
}
public function getTotaleRitenutaContributiAttribute()
{
return $this->calcola('ritenuta_contributi');
}
// Relazioni Eloquent
public function anagrafica()
{
return $this->belongsTo(Anagrafica::class, 'idanagrafica');
}
public function tipo()
{
return $this->belongsTo(Tipo::class, 'idtipodocumento');
}
public function stato()
{
return $this->belongsTo(Stato::class, 'idstatodocumento');
}
public function statoFE()
{
return $this->belongsTo(StatoFE::class, 'codice_stato_fe');
}
public function articoli()
{
return $this->hasMany(Components\Articolo::class, 'iddocumento');
}
public function righe()
{
return $this->hasMany(Components\Riga::class, 'iddocumento');
}
public function descrizioni()
{
return $this->hasMany(Components\Descrizione::class, 'iddocumento');
}
public function scontoGlobale()
{
return $this->hasOne(Components\Sconto::class, 'iddocumento');
}
public function ritenutaContributi()
{
return $this->belongsTo(RitenutaContributi::class, 'id_ritenuta_contributi');
}
// Metodi generali
public function getXML()
{
if (empty($this->progressivo_invio)) {
$fe = new FatturaElettronica($this->id);
return $fe->toXML();
}
$file = $this->uploads()->where('name', 'Fattura Elettronica')->first();
return file_get_contents($file->filepath);
}
public function isFE()
{
return !empty($this->progressivo_invio) && $this->module == 'Fatture di acquisto';
}
public function registraScadenzeFE($is_pagato = false)
{
$database = $dbo = database();
$xml = \Util\XML::read($this->getXML());
$pagamenti = $xml['FatturaElettronicaBody']['DatiPagamento']['DettaglioPagamento'];
if (!empty($pagamenti)) {
$scadenze = isset($pagamenti[0]) ? $pagamenti : [$pagamenti];
foreach ($scadenze as $scadenza) {
$data = $scadenza['DataScadenzaPagamento'] ?: $this->data;
$importo = $scadenza['ImportoPagamento'];
$dbo->insert('co_scadenziario', [
'iddocumento' => $this->id,
'data_emissione' => $this->data,
'scadenza' => $data,
'da_pagare' => -$importo,
'tipo' => 'fattura',
'pagato' => $is_pagato ? $importo : 0,
'data_pagamento' => $is_pagato ? $data : '',
], ['id' => $id_scadenza]);
}
}
return !empty($pagamenti);
}
/**
@ -187,91 +334,6 @@ class Fattura extends Document
], $this->id);
}
public function anagrafica()
{
return $this->belongsTo(Anagrafica::class, 'idanagrafica');
}
public function tipo()
{
return $this->belongsTo(Tipo::class, 'idtipodocumento');
}
public function stato()
{
return $this->belongsTo(Stato::class, 'idstatodocumento');
}
public function statoFE()
{
return $this->belongsTo(StatoFE::class, 'codice_stato_fe');
}
public function articoli()
{
return $this->hasMany(Components\Articolo::class, 'iddocumento');
}
public function righe()
{
return $this->hasMany(Components\Riga::class, 'iddocumento');
}
public function descrizioni()
{
return $this->hasMany(Components\Descrizione::class, 'iddocumento');
}
public function scontoGlobale()
{
return $this->hasOne(Components\Sconto::class, 'iddocumento');
}
public function getXML()
{
if (empty($this->progressivo_invio)) {
$fe = new FatturaElettronica($this->id);
return $fe->toXML();
}
$file = $this->uploads()->where('name', 'Fattura Elettronica')->first();
return file_get_contents($file->filepath);
}
public function isFE()
{
return !empty($this->progressivo_invio) && $this->module == 'Fatture di acquisto';
}
public function registraScadenzeFE($is_pagato = false)
{
$database = $dbo = database();
$xml = \Util\XML::read($this->getXML());
$scadenze = $xml['FatturaElettronicaBody']['DatiPagamento']['DettaglioPagamento'];
$scadenze = isset($scadenze[0]) ? $scadenze : [$scadenze];
foreach ($scadenze as $scadenza) {
$data = $scadenza['DataScadenzaPagamento'];
$importo = $scadenza['ImportoPagamento'];
$dbo->insert('co_scadenziario', [
'iddocumento' => $this->id,
'data_emissione' => $this->data,
'scadenza' => $data,
'da_pagare' => $importo,
'tipo' => 'fattura',
'pagato' => $is_pagato ? $importo : 0,
'data_pagamento' => $is_pagato ? $data : '',
], ['id' => $id_scadenza]);
}
return !empty($scadenze);
}
// Metodi statici
/**

View File

@ -17,5 +17,5 @@ return [
'numero' => empty($r['numero_esterno']) ? $r['numero'] : $r['numero_esterno'],
'note' => $r['note'],
'data' => Translator::dateToLocale($r['data']),
'logo_azienda' => !empty($logo_azienda) ? '<img src="'.$logo_azienda.'" />': '',
'logo_azienda' => !empty($logo_azienda) ? '<img src="'.$logo_azienda.'" />' : '',
];

View File

@ -24,7 +24,7 @@ switch ($resource) {
$custom['contenuto'] = 'contenuto';
$results = AJAX::completeResults($query, $where, $filter, $search, $custom);
$results = AJAX::selectResults($query, $where, $filter, $search, $limit, $custom);
foreach ($results as $key => $value) {
$matricola = \Util\Ini::getValue($r['contenuto'], 'Matricola');

View File

@ -4,8 +4,11 @@ include_once __DIR__.'/../../core.php';
switch (post('op')) {
case 'import':
$first_row = !post('first_row');
$selected = post('fields');
$include_first_row = post('include_first_row');
$selected_fields = post('fields');
$page = post('page');
$limit = 500;
// Pulizia dei campi inutilizzati
foreach ($selected as $key => $value) {
@ -16,46 +19,71 @@ switch (post('op')) {
$fields = Import::getFields($id_record);
$csv = Import::getFile($id_record, $record['id'], [
'headers' => $first_row,
]);
$csv = Import::getCSV($id_record, $record['id']);
// Gestione automatica dei valori convertiti
$csv = Filter::parse($csv);
$offset = isset($page) ? $page * $limit : 0;
// Interpretazione dei dati
$data = [];
foreach ($csv as $row) {
$data_row = [];
// Ignora la prima riga se composta da header
if ($offset == 0 && empty($include_first_row)) {
++$offset;
}
$csv = $csv->setOffset($offset)
->setLimit($limit);
// Chiavi per la lettura CSV
$keys = [];
foreach ($selected_fields as $id => $field_id) {
if (is_numeric($field_id)) {
$value = $fields[$field_id]['field'];
} else {
$value = -($id + 1);
}
$keys[] = $value;
}
// Query dei campi selezionati
$queries = [];
foreach ($fields as $key => $field) {
if (!empty($field['query'])) {
$queries[$field['field']] = $field['query'];
}
}
// Lettura dei record
$rows = $csv->fetchAssoc($keys, function ($row) use ($queries, $dbo) {
foreach ($row as $key => $value) {
$field = $fields[$selected[$key]];
if (is_int($key)) {
unset($row[$key]);
} elseif (isset($queries[$key])) {
$query = str_replace('|value|', prepare($value), $queries[$key]);
if (isset($selected[$key])) {
$name = $field['field'];
$value = $dbo->fetchOne($query)['result'];
$query = $field['query'];
if (!empty($query)) {
$query = str_replace('|value|', prepare($value), $query);
$value = $dbo->fetchArray($query)[0]['result'];
}
$data_row[$name] = $value;
$row[$key] = $value;
}
}
$data[] = $data_row;
}
return $row;
});
// Gestione automatica dei valori convertiti
$rows = iterator_to_array($rows);
$data = Filter::parse($rows);
$primary_key = post('primary_key');
// Richiamo delle operazioni specifiche
include $imports[$id_record]['import'];
flash()->info(tr('Importazione completata: _COUNT_ righe processate', [
'_COUNT_' => count($csv),
]));
$count = count($rows);
$more = $count == $limit;
echo json_encode([
'more' => $more,
'count' => $count,
]);
break;
}

View File

@ -35,16 +35,15 @@ if (empty($id_record)) {
<div class="row">
<div class="col-md-8">
{[ "type": "checkbox", "label": "'.tr('Importa prima riga').'", "name": "first_row", "extra":"", "value": "1" ]}
{[ "type": "checkbox", "label": "'.tr('Importa prima riga').'", "name": "include_first_row", "extra":"", "value": "1" ]}
</div>
<div class="col-md-4">
{[ "type": "select", "label": "'.tr('Chiave primaria').'", "name": "primary_key", "values": '.json_encode($select2).', "value": "'.$primary_key.'" ]}
</div>
</div>';
$rows = Import::getFile($id_record, $record['id'], [
'limit' => 10,
]);
$csv = Import::getCSV($id_record, $record['id']);
$rows = $csv->setLimit(10)->fetchAll();
$count = count($rows[0]);
@ -67,7 +66,7 @@ if (empty($id_record)) {
$selected = null;
foreach ($fields as $key => $value) {
if (in_array(str_to_lower($rows[0][$column]), $value['names'])) {
$first_row = 1;
$exclude_first_row = 1;
$selected = $key;
break;
}
@ -111,13 +110,59 @@ if (empty($id_record)) {
<script>
$(document).ready(function(){';
if ($first_row) {
if ($exclude_first_row) {
echo '
$("#first_row").prop("checked", false).trigger("change");';
$("#include_first_row").prop("checked", false).trigger("change");';
}
echo '
$("#save").html("<i class=\"fa fa-flag-checkered\"></i> '.tr('Avvia importazione').'");
$("#save").unbind("click");
$("#save").on("click", function() {
importPage(0);
});
});
var count = 0;
function importPage(page){
$("#main_loading").show();
data = {
id_module: "'.$id_module.'",
id_plugin: "'.$id_plugin.'",
id_record: "'.$id_record.'",
page: page,
};
$("#edit-form").ajaxSubmit({
url: globals.rootdir + "/actions.php",
data: data,
type: "post",
success: function(data) {
data = JSON.parse(data);
count += data.count;
if(data.more) {
importPage(page + 1);
} else {
$("#main_loading").fadeOut();
swal({
title: "'.tr('Importazione completata: _COUNT_ righe processate', [
'_COUNT_' => '" + count + "',
]).'",
type: "success",
});
}
},
error: function(data) {
$("#main_loading").fadeOut();
alert("'.tr('Errore').': " + data);
}
});
};
</script>';
}

View File

@ -11,46 +11,11 @@ use Modules\Interventi\TipoSessione;
switch (post('op')) {
case 'update':
$idpreventivo = post('idpreventivo');
$idcontratto = post('idcontratto');
$idcontratto_riga = post('idcontratto_riga');
$idtipointervento = post('idtipointervento');
$data_richiesta = post('data_richiesta');
$richiesta = post('richiesta');
$idsede = post('idsede');
// Collegamento intervento a contratto (se impostato)
// Oltre al collegamento al contratto, l'intervento è collegato ad una riga di pianificazione, perciò è importante considerarla se è impostata
$array = [
'idintervento' => $id_record,
'idtipointervento' => $idtipointervento,
'data_richiesta' => $data_richiesta,
'richiesta' => $richiesta,
'idsede' => $idsede ?: 0,
];
// Creazione nuova pianificazione se non era impostata
if (!empty($idcontratto) && empty($idcontratto_riga)) {
// Se questo intervento era collegato ad un altro contratto aggiorno le informazioni...
$rs = $dbo->fetchArray('SELECT id FROM co_promemoria WHERE idintervento='.prepare($id_record));
if (empty($rs)) {
$dbo->insert('co_promemoria', array_merge(['idcontratto' => $idcontratto], $array));
}
// ...altrimenti se sto cambiando contratto aggiorno solo l'id del nuovo contratto
else {
$dbo->update('co_promemoria', ['idcontratto' => $idcontratto], ['idintervento' => $id_record]);
}
}
// Pianificazione già impostata, aggiorno solo il codice intervento
elseif (!empty($idcontratto) && !empty($idcontratto_riga)) {
$dbo->update('co_promemoria', $array, ['idcontratto' => $idriga, 'id' => $idcontratto_riga]);
}
// Se non è impostato nessun contratto o riga, tolgo il collegamento dell'intervento al contratto
elseif (empty($idcontratto)) {
// Rimozione del collegamento al promemoria
if (!empty($idcontratto_riga) && $intervento->id_contratto != $idcontratto) {
$dbo->update('co_promemoria', ['idintervento' => null], ['idintervento' => $id_record]);
}
@ -58,33 +23,33 @@ switch (post('op')) {
$sconto = post('sconto_globale');
// Salvataggio modifiche intervento
$dbo->update('in_interventi', [
'data_richiesta' => $data_richiesta,
'richiesta' => $richiesta,
'descrizione' => post('descrizione'),
'informazioniaggiuntive' => post('informazioniaggiuntive'),
$intervento->data_richiesta = post('data_richiesta');
$intervento->richiesta = post('richiesta');
$intervento->descrizione = post('descrizione');
$intervento->informazioniaggiuntive = post('informazioniaggiuntive');
'idanagrafica' => post('idanagrafica'),
'idclientefinale' => post('idclientefinale'),
'idreferente' => post('idreferente'),
'idtipointervento' => $idtipointervento,
$intervento->idanagrafica = post('idanagrafica');
$intervento->idclientefinale = post('idclientefinale');
$intervento->idreferente = post('idreferente');
$intervento->idtipointervento = post('idtipointervento');
'idstatointervento' => post('idstatointervento'),
'idsede' => $idsede,
'idautomezzo' => post('idautomezzo'),
'id_preventivo' => $idpreventivo,
$intervento->idstatointervento = post('idstatointervento');
$intervento->idsede = post('idsede');
$intervento->idautomezzo = post('idautomezzo');
$intervento->id_preventivo = post('idpreventivo');
$intervento->id_contratto = $idcontratto;
'sconto_globale' => $sconto,
'tipo_sconto_globale' => $tipo_sconto,
$intervento->sconto_globale = $sconto;
$intervento->tipo_sconto_globale = $tipo_sconto;
'id_documento_fe' => post('id_documento_fe'),
'codice_cup' => post('codice_cup'),
'codice_cig' => post('codice_cig'),
'num_item' => post('num_item'),
], ['id' => $id_record]);
$intervento->id_documento_fe = post('id_documento_fe');
$intervento->num_item = post('num_item');
$intervento->codice_cup = post('codice_cup');
$intervento->codice_cig = post('codice_cig');
$intervento->save();
$stato = $dbo->selectOne('in_statiintervento', '*', ['idstatointervento' => post('idstatointervento')]);
// Notifica chiusura intervento
$stato = $dbo->selectOne('in_statiintervento', '*', ['idstatointervento' => post('idstatointervento')]);
if (!empty($stato['notifica']) && !empty($stato['destinatari']) && $stato['idstatointervento'] != $record['idstatointervento']) {
$n = new Notifications\EmailNotification();
@ -135,59 +100,46 @@ switch (post('op')) {
$intervento->idsede = post('idsede');
}
$intervento->id_preventivo = post('$idpreventivo');
$intervento->id_preventivo = post('idpreventivo');
$intervento->id_contratto = post('idcontratto');
$intervento->richiesta = $richiesta;
$intervento->save();
// Collego l'intervento al contratto
if (!empty($idcontratto)) {
$array = [
// Se è specificato che l'intervento fa parte di una pianificazione aggiorno il codice dell'intervento sulla riga della pianificazione
if (!empty($idcontratto_riga)) {
$dbo->update('co_promemoria', [
'idintervento' => $id_record,
'idtipointervento' => $idtipointervento,
'data_richiesta' => $data_richiesta,
'richiesta' => $richiesta,
'idsede' => $idsede ?: 0,
];
], ['idcontratto' => $idcontratto, 'id' => $idcontratto_riga]);
// Se è specificato che l'intervento fa parte di una pianificazione aggiorno il codice dell'intervento sulla riga della pianificazione
if (!empty($idcontratto_riga)) {
$dbo->update('co_promemoria', $array, ['idcontratto' => $idcontratto, 'id' => $idcontratto_riga]);
//copio le righe dal promemoria all'intervento
$dbo->query('INSERT INTO in_righe_interventi (descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,idintervento,sconto,sconto_unitario,tipo_sconto) SELECT descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,'.$id_record.',sconto,sconto_unitario,tipo_sconto FROM co_promemoria_righe WHERE id_promemoria = '.$idcontratto_riga);
//copio le righe dal promemoria all'intervento
$dbo->query('INSERT INTO in_righe_interventi (descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,idintervento,sconto,sconto_unitario,tipo_sconto) SELECT descrizione, qta,um,prezzo_vendita,prezzo_acquisto,idiva,desc_iva,iva,'.$id_record.',sconto,sconto_unitario,tipo_sconto FROM co_promemoria_righe WHERE id_promemoria = '.$idcontratto_riga.' ');
//copio gli articoli dal promemoria all'intervento
$dbo->query('INSERT INTO mg_articoli_interventi (idarticolo, idintervento,descrizione,prezzo_acquisto,prezzo_vendita,sconto, sconto_unitario, tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto) SELECT idarticolo, '.$id_record.',descrizione,prezzo_acquisto,prezzo_vendita,sconto,sconto_unitario,tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto FROM co_promemoria_articoli WHERE id_promemoria = '.$idcontratto_riga);
//copio gli articoli dal promemoria all'intervento
$dbo->query('INSERT INTO mg_articoli_interventi (idarticolo, idintervento,descrizione,prezzo_acquisto,prezzo_vendita,sconto, sconto_unitario, tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto) SELECT idarticolo, '.$id_record.',descrizione,prezzo_acquisto,prezzo_vendita,sconto,sconto_unitario,tipo_sconto,idiva,desc_iva,iva,idautomezzo, qta, um, abilita_serial, idimpianto FROM co_promemoria_articoli WHERE id_promemoria = '.$idcontratto_riga.' ');
// Copia degli allegati
$alleagti = Uploads::copy([
'id_plugin' => Plugins::get('Pianificazione interventi')['id'],
'id_record' => $idcontratto_riga,
], [
'id_module' => $id_module,
'id_record' => $id_record,
]);
// Copia degli allegati
$alleagti = Uploads::copy([
'id_plugin' => Plugins::get('Pianificazione interventi')['id'],
'id_record' => $idcontratto_riga,
], [
'id_module' => $id_module,
'id_record' => $id_record,
]);
if (!$alleagti) {
$errors = error_get_last();
flash()->warning(tr('Errore durante la copia degli allegati'));
}
if (!$alleagti) {
$errors = error_get_last();
flash()->warning(tr('Errore durante la copia degli allegati'));
}
// Decremento la quantità per ogni articolo copiato
$rs_articoli = $dbo->fetchArray('SELECT * FROM mg_articoli_interventi WHERE idintervento = '.$id_record.' ');
foreach ($rs_articoli as $rs_articolo) {
add_movimento_magazzino($rs_articolo['idarticolo'], -$rs_articolo['qta'], ['idautomezzo' => $rs_articolo['idautomezzo'], 'idintervento' => $id_record]);
}
} else {
$dbo->insert('co_promemoria', [
'idcontratto' => $idcontratto,
'idintervento' => $id_record,
'idtipointervento' => $idtipointervento,
'data_richiesta' => $data_richiesta,
'richiesta' => $richiesta,
'idsede' => $idsede ?: 0,
]);
// Decremento la quantità per ogni articolo copiato
$rs_articoli = $dbo->fetchArray('SELECT * FROM mg_articoli_interventi WHERE idintervento = '.$id_record.' ');
foreach ($rs_articoli as $rs_articolo) {
add_movimento_magazzino($rs_articolo['idarticolo'], -$rs_articolo['qta'], ['idautomezzo' => $rs_articolo['idautomezzo'], 'idintervento' => $id_record]);
}
}
@ -265,7 +217,7 @@ switch (post('op')) {
$dbo->query($query);
// Eliminazione dell'intervento
$query = 'DELETE FROM in_interventi WHERE id='.prepare($id_record).' '.Modules::getAdditionalsQuery($id_module);
$query = 'DELETE FROM in_interventi WHERE id='.prepare($id_record);
$dbo->query($query);
// Elimino i collegamenti degli articoli a questo intervento
@ -371,7 +323,7 @@ switch (post('op')) {
case 'delriga':
$idriga = post('idriga');
$dbo->query('DELETE FROM in_righe_interventi WHERE id='.prepare($idriga).' '.Modules::getAdditionalsQuery($id_module));
$dbo->query('DELETE FROM in_righe_interventi WHERE id='.prepare($idriga));
break;
@ -426,7 +378,7 @@ switch (post('op')) {
$articolo->save();
// Aggiorno l'automezzo dell'intervento
$dbo->query('UPDATE in_interventi SET idautomezzo='.prepare(post('idautomezzo')).' WHERE id='.prepare($id_record).' '.Modules::getAdditionalsQuery($id_module));
$dbo->query('UPDATE in_interventi SET idautomezzo='.prepare(post('idautomezzo')).' WHERE id='.prepare($id_record));
if (!empty($serials)) {
if ($old_qta > $qta) {
@ -536,7 +488,7 @@ switch (post('op')) {
$id_tecnico = post('id_tecnico');
// Verifico se l'intervento è collegato ad un contratto
// TODO: utilizzare campo id_contratto in in_interventi come avviene già per i preventivi (id_preventivo) dalla 2.4.2
// TODO: utilizzare campo id_contratto in in_interventi come avviene già per i preventivi (id_preventivo) dalla 2.4.2
$rs = $dbo->fetchArray('SELECT idcontratto FROM co_promemoria WHERE idintervento='.prepare($id_record));
$idcontratto = $rs[0]['idcontratto'];

View File

@ -5,7 +5,6 @@ include_once __DIR__.'/../../core.php';
// Rimuovo session usate sui select combinati (sedi, preventivi, contratti, impianti)
unset($_SESSION['superselect']['idanagrafica']);
unset($_SESSION['superselect']['idsede']);
unset($_SESSION['superselect']['non_fatturato']);
// Calcolo del nuovo codice
$new_codice = \Modules\Interventi\Intervento::getNextCodice();

View File

@ -4,7 +4,7 @@ include_once __DIR__.'/../../core.php';
$show_prezzi = Auth::user()['gruppo'] != 'Tecnici' || (Auth::user()['gruppo'] == 'Tecnici' && setting('Mostra i prezzi al tecnico'));
$query = 'SELECT *, (SELECT codice FROM mg_articoli WHERE id=mg_articoli_interventi.idarticolo) AS codice, mg_articoli_interventi.id AS idriga, (SELECT prc_guadagno FROM mg_listini WHERE id=(SELECT idlistino_vendite FROM an_anagrafiche WHERE idanagrafica=(SELECT idanagrafica FROM in_interventi WHERE id=mg_articoli_interventi.idintervento) ) ) AS prc_guadagno FROM mg_articoli_interventi WHERE idintervento='.prepare($id_record).' '.Modules::getAdditionalsQuery('Magazzino');
$query = 'SELECT *, (SELECT codice FROM mg_articoli WHERE id=mg_articoli_interventi.idarticolo) AS codice, mg_articoli_interventi.id AS idriga, (SELECT prc_guadagno FROM mg_listini WHERE id=(SELECT idlistino_vendite FROM an_anagrafiche WHERE idanagrafica=(SELECT idanagrafica FROM in_interventi WHERE id=mg_articoli_interventi.idintervento) ) ) AS prc_guadagno FROM mg_articoli_interventi WHERE idintervento='.prepare($id_record);
$rs = $dbo->fetchArray($query);
if (!empty($rs)) {

View File

@ -8,7 +8,7 @@ if (file_exists(__DIR__.'/../../../core.php')) {
$show_prezzi = Auth::user()['gruppo'] != 'Tecnici' || (Auth::user()['gruppo'] == 'Tecnici' && setting('Mostra i prezzi al tecnico'));
$query = 'SELECT * FROM in_righe_interventi WHERE idintervento='.prepare($id_record).' '.Modules::getAdditionalsQuery('Magazzino').' ORDER BY id ASC';
$query = 'SELECT * FROM in_righe_interventi WHERE idintervento='.prepare($id_record).' ORDER BY id ASC';
$rs2 = $dbo->fetchArray($query);
if (count($rs2) > 0) {

View File

@ -48,6 +48,7 @@ switch ($resource) {
// Periodo per selezionare interventi
$today = date('Y-m-d');
$period_end = date('Y-m-d', strtotime($today.' +7 days'));
$period_start = date('Y-m-d', strtotime($today.' -2 months'));
$query = "SELECT `in_interventi`.`id`,
`in_interventi`.`codice`,
@ -64,7 +65,7 @@ switch ($resource) {
`in_interventi`.`firma_file`,
IF(firma_data = '0000-00-00 00:00:00', '', firma_data) AS `firma_data`,
`in_interventi`.firma_nome,
(SELECT GROUP_CONCAT( CONCAT(my_impianti.matricola, ' - ', my_impianti.nome) SEPARATOR ', ') FROM (my_impianti_interventi INNER JOIN my_impianti ON my_impianti_interventi.idimpianto=my_impianti.id) WHERE my_impianti_interventi.idintervento = `in_interventi`.`id`) AS `impianti`,
(SELECT GROUP_CONCAT(CONCAT(my_impianti.matricola, ' - ', my_impianti.nome) SEPARATOR ', ') FROM (my_impianti_interventi INNER JOIN my_impianti ON my_impianti_interventi.idimpianto=my_impianti.id) WHERE my_impianti_interventi.idintervento = `in_interventi`.`id`) AS `impianti`,
(SELECT MAX(`orario_fine`) FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `data`,
(SELECT GROUP_CONCAT(DISTINCT ragione_sociale SEPARATOR ', ') FROM `in_interventi_tecnici` INNER JOIN `an_anagrafiche` ON `in_interventi_tecnici`.`idtecnico` = `an_anagrafiche`.`idanagrafica` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) AS `tecnici`,
`in_statiintervento`.`colore` AS `bgcolor`,
@ -74,9 +75,9 @@ switch ($resource) {
INNER JOIN `in_statiintervento` ON `in_interventi`.`idstatointervento` = `in_statiintervento`.`idstatointervento`
INNER JOIN `an_anagrafiche` ON `in_interventi`.`idanagrafica` = `an_anagrafiche`.`idanagrafica`
LEFT JOIN `an_sedi` ON `in_interventi`.`idsede` = `an_sedi`.`id`
WHERE (SELECT MAX(`orario_fine`) FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id`) <= :period_end";
WHERE EXISTS(SELECT `orario_fine` FROM `in_interventi_tecnici` WHERE `in_interventi_tecnici`.`idintervento` = `in_interventi`.`id` AND `orario_fine` BETWEEN :period_start AND :period_end)";
// TODO: rimosse seguenti clausole:
// TODO: rimosse le seguenti clausole
// WHERE `in_interventi`.idstatointervento IN(SELECT idstatointervento FROM in_statiintervento WHERE app_download=1)
// nel database ufficiale manca in_statiintervento.app_download
@ -86,6 +87,7 @@ switch ($resource) {
$parameters = [
':period_end' => $period_end,
':period_start' => $period_start,
];
break;

View File

@ -42,13 +42,11 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
</div>
</div>
<!-- RIGA 2 -->
<div class="row">
<div class="col-md-6">
<?php
if (($record['idpreventivo'] != '')) {
if (!empty($record['idpreventivo'])) {
echo '
'.Modules::link('Preventivi', $record['idpreventivo'], null, null, 'class="pull-right"');
}
@ -59,22 +57,16 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
<div class="col-md-6">
<?php
/*$rs = $dbo->fetchArray('SELECT id, idcontratto FROM co_promemoria WHERE idintervento='.prepare($id_record));
if (count($rs) == 1) {
$idcontratto = $rs[0]['idcontratto'];
$idcontratto_riga = $rs[0]['id'];
} else {
$idcontratto = '';
$idcontratto_riga = '';
}*/
$idcontratto_riga = $dbo->fetchOne('SELECT id FROM co_promemoria WHERE idintervento='.prepare($id_record))['id'];
if (($record['idcontratto'] != '')) {
if (!empty($record['idcontratto'])) {
echo '
'.Modules::link('Contratti', $record['idcontratto'], null, null, 'class="pull-right"');
}
?>
{[ "type": "select", "label": "<?php echo tr('Contratto'); ?>", "name": "idcontratto", "value": "<?php echo $record['idcontratto']; ?>", "ajax-source": "contratti", "readonly": "<?php echo $record['flag_completato']; ?>" ]}
{[ "type": "select", "label": "<?php echo tr('Contratto'); ?>", "name": "idcontratto", "value": "<?php echo $record['id_contratto']; ?>", "ajax-source": "contratti", "readonly": "<?php echo $record['flag_completato']; ?>" ]}
<input type='hidden' name='idcontratto_riga' value='<?php echo $idcontratto_riga; ?>'>
</div>
</div>
@ -152,7 +144,7 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
?>
<!-- Fatturazione Elettronica PA-->
<div class="panel panel-primary <?php echo (($record['tipo_anagrafica']) == 'Ente pubblico' or ($record['tipo_anagrafica']) == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel panel-primary <?php echo ($record['tipo_anagrafica'] == 'Ente pubblico' || $record['tipo_anagrafica'] == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Dati appalto'); ?>
<?php if (!empty($record['idcontratto'])) {

View File

@ -2,6 +2,17 @@
include_once __DIR__.'/../../core.php';
use Modules\Interventi\Intervento;
if (isset($id_record)) {
$record = $dbo->fetchOne('SELECT *, (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica) AS tipo_anagrafica, (SELECT completato FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS flag_completato, IF((in_interventi.idsede = 0), (SELECT idzona FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica), (SELECT idzona FROM an_sedi WHERE id = in_interventi.idsede)) AS idzona, (SELECT colore FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS colore, (SELECT idcontratto FROM co_promemoria WHERE idintervento=in_interventi.id LIMIT 0,1) AS idcontratto, in_interventi.id_preventivo as idpreventivo FROM in_interventi WHERE id='.prepare($id_record).Modules::getAdditionalsQuery($id_module));
$intervento = Intervento::find($id_record);
$record = $dbo->fetchOne('SELECT *,
(SELECT tipo FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica) AS tipo_anagrafica,
(SELECT completato FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS flag_completato,
IF((in_interventi.idsede = 0), (SELECT idzona FROM an_anagrafiche WHERE idanagrafica = in_interventi.idanagrafica), (SELECT idzona FROM an_sedi WHERE id = in_interventi.idsede)) AS idzona,
(SELECT colore FROM in_statiintervento WHERE idstatointervento=in_interventi.idstatointervento) AS colore,
in_interventi.id_preventivo as idpreventivo,
in_interventi.id_contratto as idcontratto
FROM in_interventi WHERE id='.prepare($id_record));
}

View File

@ -25,14 +25,6 @@ trait RelationTrait
{
}
public function fixRivalsaINPS()
{
}
public function fixRitenutaAcconto()
{
}
public function getSubtotaleAttribute()
{
return $this->prezzo_vendita * $this->qta;

View File

@ -4,6 +4,7 @@ namespace Modules\Interventi;
use Common\Document;
use Modules\Anagrafiche\Anagrafica;
use Modules\Contratti\Contratto;
use Modules\Interventi\Components\Articolo;
use Modules\Interventi\Components\Riga;
use Modules\Preventivi\Preventivo;
@ -46,7 +47,12 @@ class Intervento extends Document
public function preventivo()
{
return $this->hasOne(Preventivo::class, 'id_preventivo');
return $this->belongsTo(Preventivo::class, 'id_preventivo');
}
public function contratto()
{
return $this->belongsTo(Contratto::class, 'id_contratto');
}
public function stato()

View File

@ -3,5 +3,5 @@
include_once __DIR__.'/../../core.php';
if (isset($id_record)) {
$record = $dbo->fetchOne('SELECT *, (SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica=my_impianti.idanagrafica) AS cliente FROM my_impianti WHERE id='.prepare($id_record).Modules::getAdditionalsQuery($id_module));
$record = $dbo->fetchOne('SELECT *, (SELECT ragione_sociale FROM an_anagrafiche WHERE idanagrafica=my_impianti.idanagrafica) AS cliente FROM my_impianti WHERE id='.prepare($id_record));
}

View File

@ -22,11 +22,8 @@ switch (post('op')) {
$idanagrafica = post('idanagrafica');
$data = post('data');
// Leggo se l'ordine è cliente o fornitore
$tipo = $dbo->fetchOne('SELECT id FROM or_tipiordine WHERE dir='.prepare($dir));
$anagrafica = Anagrafica::find($idanagrafica);
$tipo = Tipo::find($tipo['id']);
$tipo = Tipo::where('dir', $dir)->first();
$ordine = Ordine::build($anagrafica, $tipo, $data);
$id_record = $ordine->id;
@ -348,88 +345,57 @@ switch (post('op')) {
break;
case 'ordine_da_preventivo':
// Aggiunta di un preventivo in ordine
case 'add_preventivo':
$preventivo = \Modules\Preventivi\Preventivo::find(post('id_preventivo'));
$idanagrafica = post('idanagrafica');
$idpreventivo = post('idpreventivo');
// Creazione della fattura al volo
if (post('create_document') == 'on') {
$tipo = Tipo::where('dir', $dir)->first();
$data = post('data');
$ordine = Ordine::build($preventivo->anagrafica, $tipo, post('data'));
$ordine->idpagamento = $preventivo->idpagamento;
$ordine->save();
// Leggo se l'ordine è cliente o fornitore
$rs = $dbo->fetchArray('SELECT id FROM or_tipiordine WHERE dir='.prepare($dir));
$idtipoordine = $rs[0]['id'];
$id_record = $ordine->id;
}
if (post('idanagrafica') !== null) {
$numero = get_new_numeroordine($data);
if ($dir == 'entrata') {
$numero_esterno = get_new_numerosecondarioordine($data);
} else {
$numero_esterno = '';
}
$parziale = false;
$righe = $preventivo->getRighe();
foreach ($righe as $riga) {
if (post('evadere')[$riga->id] == 'on') {
$qta = post('qta_da_evadere')[$riga->id];
$campo = ($dir == 'entrata') ? 'idpagamento_vendite' : 'idpagamento_acquisti';
$copia = $riga->copiaIn($ordine, $qta);
// Tipo di pagamento predefinito dall'anagrafica
$query = 'SELECT id FROM co_pagamenti WHERE id=(SELECT '.$campo.' AS pagamento FROM an_anagrafiche WHERE idanagrafica='.prepare($idanagrafica).')';
$rs = $dbo->fetchArray($query);
$idpagamento = isset($rs[0]) ? $rs[0]['id'] : null;
// Se l'ordine è un ordine cliente e non è stato associato un pagamento predefinito al cliente leggo il pagamento dalle impostazioni
if ($dir == 'entrata' && empty($idpagamento)) {
$idpagamento = setting('Tipo di pagamento predefinito');
}
$query = 'INSERT INTO or_ordini( numero, numero_esterno, idanagrafica, idtipoordine, idpagamento, data, idstatoordine ) VALUES ( '.prepare($numero).', '.prepare($numero_esterno).', '.prepare($idanagrafica).', '.prepare($idtipoordine).', '.prepare($idpagamento).', '.prepare($data).", (SELECT `id` FROM `or_statiordine` WHERE `descrizione`='Bozza') )";
$dbo->query($query);
$id_record = $dbo->lastInsertedID();
flash()->info(tr('Aggiunto ordine numero _NUM_!', [
'_NUM_' => $numero,
]));
// Lettura di tutte le righe della tabella in arrivo
// Inserisco anche le righe descrittive
foreach (post('evadere') as $i => $value) {
// Processo solo le righe da evadere
if (post('evadere')[$i] == 'on') {
$descrizione = post('descrizione')[$i];
$prezzo = post('subtot')[$i];
$qta = post('qta_da_evadere')[$i];
$idiva = post('idiva')[$i];
$um = post('um')[$i];
$subtot = $prezzo * $qta;
$idarticolo = post('idarticolo')[$i];
$sconto = post('sconto')[$i];
// Ottengo le informazioni sullo sconto
$qprc = 'SELECT tipo_sconto, sconto_unitario FROM co_righe_preventivi WHERE id='.prepare($i);
$rsprc = $dbo->fetchArray($qprc);
$sconto_unitario = $rsprc[0]['sconto_unitario'];
$tipo_sconto = $rsprc[0]['tipo_sconto'];
$sconto = $sconto * $qta;
// Calcolo iva
$query = 'SELECT descrizione, percentuale, indetraibile FROM co_iva WHERE id='.prepare($idiva);
$rs = $dbo->fetchArray($query);
$iva = ($subtot - $sconto) / 100 * $rs[0]['percentuale'];
$iva_indetraibile = $iva / 100 * $rs[0]['indetraibile'];
$query = 'INSERT INTO or_righe_ordini(idordine, idarticolo, idpreventivo, idiva, desc_iva, iva, iva_indetraibile, descrizione, subtotale, sconto, sconto_unitario, tipo_sconto, um, qta, is_descrizione, `order`) VALUES('.prepare($id_record).', '.prepare($idarticolo).', '.prepare($idpreventivo).', '.prepare($idiva).', '.prepare($rs[0]['descrizione']).', '.prepare($iva).', '.prepare($iva_indetraibile).', '.prepare($descrizione).', '.prepare($subtot).', '.prepare($sconto).', '.prepare($sconto_unitario).', '.prepare($tipo_sconto).', '.prepare($um).', '.prepare($qta).', '.prepare(empty($qta)).', (SELECT IFNULL(MAX(`order`) + 1, 0) FROM or_righe_ordini AS t WHERE idordine='.prepare($id_record).'))';
$dbo->query($query);
// Aggiornamento seriali dalla riga dell'ordine
if ($copia->isArticolo()) {
$copia->movimenta($copia->qta);
}
$copia->save();
}
// Ricalcolo inps, ritenuta e bollo
if ($dir == 'entrata') {
ricalcola_costiagg_ordine($id_record);
} else {
ricalcola_costiagg_ordine($id_record);
if ($riga->qta != $riga->qta_evasa) {
$parziale = true;
}
}
// Aggiornamento sconto
if (post('evadere')[$preventivo->scontoGlobale->id] == 'on') {
$ordine->tipo_sconto_globale = $preventivo->tipo_sconto_globale;
$ordine->sconto_globale = $preventivo->tipo_sconto_globale == 'PRC' ? $preventivo->sconto_globale : $preventivo->sconto_globale;
$ordine->save();
$ordine->updateSconto();
}
ricalcola_costiagg_ordine($id_record);
flash()->info(tr('Preventivo _NUM_ aggiunto!', [
'_NUM_' => $preventivo->numero,
]));
break;
}

View File

@ -2,32 +2,26 @@
include_once __DIR__.'/../../core.php';
if (!in_array($record['stato'], ['Fatturato'])) {
echo '
<div class="dropdown">
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
echo '
<div class="dropdown">
<button class="btn btn-info dropdown-toggle '.(!in_array($record['stato'], ['Fatturato', 'Evaso']) ? '' : 'disabled').'" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-magic"></i>&nbsp;'.tr('Crea').'...
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">';
if (in_array($record['stato'], ['Bozza', 'Parzialmente evaso'])) {
echo '
<li>
<a data-href="'.$rootdir.'/modules/fatture/crea_documento.php?id_module='.$id_module.'&id_record='.$id_record.'&documento=ddt" data-toggle="modal" data-title="'.tr('Crea ddt').'"><i class="fa fa-file-o"></i>&nbsp;'.tr('ddt').'
</a>
</li>';
}
if (in_array($record['stato'], ['Bozza', 'Evaso', 'Parzialmente evaso', 'Parzialmente fatturato'])) {
echo '
<li>
<a data-href="'.$rootdir.'/modules/fatture/crea_documento.php?id_module='.$id_module.'&id_record='.$id_record.'&documento=fattura" data-toggle="modal" data-title="'.tr('Crea fattura').'"><i class="fa fa-file"></i>&nbsp;'.tr('fattura').'
</a>
</li>';
}
echo '
<li>
<a data-href="'.$structure->fileurl('crea_documento.php').'?id_module='.$id_module.'&id_record='.$id_record.'&documento=ddt" data-toggle="modal" data-title="'.tr('Crea ddt').'" class="'.(in_array($record['stato'], ['Bozza', 'Parzialmente evaso']) ? '' : 'disabled').'"><i class="fa fa-file-o"></i>&nbsp;'.tr('ddt').'
</a>
</li>';
echo '
</ul>
</div>';
}
<li>
<a data-href="'.$structure->fileurl('crea_documento.php').'?id_module='.$id_module.'&id_record='.$id_record.'&documento=fattura" data-toggle="modal" data-title="'.tr('Crea fattura').'" class="'.(in_array($record['stato'], ['Bozza', 'Parzialmente fatturato']) ? '' : 'disabled').'"><i class="fa fa-file"></i>&nbsp;'.tr('fattura').'
</a>
</li>';
echo '
</ul>
</div>';

View File

@ -4,268 +4,36 @@ include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
$data = [
'preventivo' => [
'table' => 'co_preventivi',
'rows' => 'co_righe_preventivi',
'id' => 'idpreventivo',
'condition' => '',
],
];
$documento = get('documento');
$pos = 'preventivo';
$op = 'ordine_da_preventivo';
$head = tr('Preventivo numero _NUM_');
$table = $data[$pos]['table'];
$rows = $data[$pos]['rows'];
$id = $data[$pos]['id'];
$row = str_replace('id', 'id_riga_', $id);
$module_name = 'Ordini cliente';
$op = !empty(get('op')) ? get('op') : $op;
$button = tr('Crea ordine');
$button = !empty(get('op')) ? tr('Aggiungi') : $button;
// Info documento
$rs = $dbo->fetchArray('SELECT * FROM '.$table.' WHERE id='.prepare($id_record));
$numero = !empty($rs[0]['numero_esterno']) ? $rs[0]['numero_esterno'] : $rs[0]['numero'];
$idanagrafica = $rs[0]['idanagrafica'];
$idsede = $rs[0]['idsede'];
$idpagamento = $rs[0]['idpagamento'];
$idconto = $rs[0]['idconto'];
/*
Form di inserimento riga documento
*/
echo '
<p>'.str_replace('_NUM_', $numero, $head).'.</p>';
// Selezione articoli del preventivo da copiare nell'ordine, usando l'ordinamento scelto dall'utente
$rs = $dbo->fetchArray('SELECT * FROM '.$table.' INNER JOIN '.$rows.' ON '.$table.'.id='.$rows.'.'.$id.' WHERE '.$table.'.id='.prepare($id_record).' ORDER BY `order`');
if (!empty($rs)) {
echo '
<p>'.tr('Seleziona le righe e le relative quantità da inserire nell\'ordine.').'.</p>
<form action="'.$rootdir.'/editor.php?id_module='.Modules::get($module_name)['id'].(!empty(get('iddocumento')) ? '&id_record='.get('iddocumento') : '').'" method="post">
<input type="hidden" name="'.$id.'" value="'.$id_record.'">
<input type="hidden" name="idanagrafica" value="'.$idanagrafica.'">
<input type="hidden" name="idsede" value="'.$idsede.'">
<input type="hidden" name="idconto" value="'.$idconto.'">
<input type="hidden" name="idpagamento" value="'.$idpagamento.'">
<input type="hidden" name="iddocumento" value="'.$id_record.'">
<input type="hidden" name="op" value="'.$op.'">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="dir" value="'.$dir.'">
<div class="row">
<div class="col-md-6">
{[ "type": "date", "label": "'.tr('Data del documento').'", "name": "data", "required": 1, "value": "-now-" ]}
</div>
</div>
<div class="clearfix"></div>
<br>
<table class="table table-striped table-hover table-condensed">
<tr>
<th>'.tr('Descrizione').'</th>
<th width="10%">'.tr('Q.').'</th>
<th width="15%">'.tr('Q. da evadere').'</th>
<th width="20%">'.tr('Subtot.').'</th>
<th width="20%">'.tr('Seriali').'</th>
</tr>';
$totale = 0.00;
foreach ($rs as $i => $r) {
// Descrizione
echo '
<tr>
<td '.($r['is_descrizione'] ? 'colspan="5"' : '').' >
<input type="hidden" name="abilita_serial['.$r['id'].']" value="'.$r['abilita_serial'].'" />
<input type="hidden" id="idarticolo_'.$i.'" name="idarticolo['.$r['id'].']" value="'.$r['idarticolo'].'" />
<input type="hidden" id="descrizione_'.$i.'" name="descrizione['.$r['id'].']" value="'.$r['descrizione'].'" />';
// Checkbox - da evadere?
echo '
<input type="checkbox" checked="checked" id="checked_'.$i.'" name="evadere['.$r['id'].']" value="on" onclick="ricalcola_subtotale_riga('.$i.');" />';
echo nl2br($r['descrizione']);
echo '
</td>';
if ($r['is_descrizione']) {
continue;
}
// Q.tà rimanente
echo '
<td>
<input type="hidden" id="qtamax_'.$i.'" value="'.($r['qta']).'" />
<input type="hidden" id="um_'.$i.'" name="um['.$r['id'].']" value="'.$r['um'].'" />
<p class="text-center">'.Translator::numberToLocale($r['qta'], 'qta').'</p>
</td>';
// Q.tà da evadere
echo '
<td>
{[ "type": "number", "name": "qta_da_evadere['.$r['id'].']", "id": "qta_'.$i.'", "required": 1, "value": "'.$r['qta'].'", "extra" : "onkeyup=\"ricalcola_subtotale_riga('.$i.');\"", "decimals": "qta", "min-value": "0" ]}
</td>';
// Subtotale
$subtotale = $r['subtotale'] / $r['qta'] * ($r['qta']);
$sconto = $r['sconto'] / $r['qta'] * ($r['qta']);
$iva = $r['iva'] / $r['qta'] * ($r['qta']);
echo '
<td>
<input type="hidden" id="subtot_'.$i.'" name="subtot['.$r['id'].']" value="'.($r['subtotale'] / $r['qta']).'" />
<input type="hidden" id="sconto_'.$i.'" name="sconto['.$r['id'].']" value="'.($r['sconto'] / $r['qta']).'" />
<input type="hidden" id="idiva_'.$i.'" name="idiva['.$r['id'].']" value="'.$r['idiva'].'" />
<input type="hidden" id="iva_'.$i.'" name="iva['.$r['id'].']" value="'.($r['iva'] / $r['qta']).'" />
<big id="subtotale_'.$i.'">'.Translator::numberToLocale($subtotale - $sconto + $iva).' &euro;</big><br/>
<small style="color:#777;" id="subtotaledettagli_'.$i.'">'.Translator::numberToLocale($subtotale - $sconto).' + '.Translator::numberToLocale($iva).'</small>
</td>';
// Seriali
echo '
<td>';
if (!empty($r['abilita_serial'])) {
$values = $dbo->fetchArray('SELECT DISTINCT serial FROM mg_prodotti WHERE dir=\''.$dir.'\' AND '.$row.' = \''.$r['id'].'\' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti WHERE serial IS NOT NULL AND dir=\''.$dir.'\' AND '.$data[$pos]['condition'].')');
echo '
{[ "type": "select", "name": "serial['.$i.']['.$r['id'].']", "id": "serial_'.$i.'", "multiple": 1, "values": "query=SELECT DISTINCT serial AS id, serial AS descrizione FROM mg_prodotti WHERE dir=\''.$dir.'\' AND '.$row.' = \''.$r['id'].'\' AND serial IS NOT NULL AND serial NOT IN (SELECT serial FROM mg_prodotti WHERE serial IS NOT NULL AND dir=\''.$dir.'\' AND '.$data[$pos]['condition'].')", "value": "'.implode(',', array_column($values, 'serial')).'", "extra": "data-maximum=\"'.intval($r['qta_rimanente']).'\"" ]}
';
} else {
echo '-';
}
echo '
</td>
</tr>';
$totale += $subtotale - $sconto + $iva;
}
// Totale
echo '
<tr>
<td colspan="4" align="right" class="text-right">
<b>'.tr('Totale').':</b>
</td>
<td class="text-right" colspan="2">
<big id="totale">'.Translator::numberToLocale($totale).' &euro;</big>
</td>
</tr>
</table>';
echo '
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type="submit" id="submit_btn" class="btn btn-primary pull-right">
<i class="fa fa-plus"></i> '.$button.'
</button>
</div>
</div>
</form>';
if (get('documento') == 'fattura') {
$final_module = $module['name'] == 'Ordini cliente' ? 'Fatture di vendita' : 'Fatture di acquisto';
} else {
echo '
<p>'.tr('Non ci sono articoli da evadere').'...</p>';
$final_module = $module['name'] == 'Ordini cliente' ? 'Ddt di vendita' : 'Ddt di acquisto';
}
echo '
<script src="'.$rootdir.'/lib/init.js"></script>';
$dir = $module['name'] == 'Ordini cliente' ? 'entrata' : 'uscita';
?>
$options = [
'op' => 'add_ordine',
'id_importazione' => 'id_ordine',
'final_module' => $final_module,
'original_module' => $module['name'],
'sql' => [
'table' => 'or_ordini',
'rows' => 'or_righe_ordini',
'id_rows' => 'idordine',
],
'serials' => [
'id_riga' => 'id_riga_ordine',
'condition' => '(id_riga_ddt IS NOT NULL OR id_riga_documento IS NOT NULL)',
],
'button' => tr('Aggiungi'),
'dir' => $dir,
'create_document' => true,
];
<script type="text/javascript">
function ricalcola_subtotale_riga( r ){
subtot = $("#subtot_"+r).val();
sconto = $("#sconto_"+r).val();
iva = $("#iva_"+r).val();
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
qtamax = $("#qtamax_"+r).val() ? $("#qtamax_"+r).val() : 0;
subtot = parseFloat(subtot);
sconto = parseFloat(sconto);
iva = parseFloat(iva);
qtamax = parseFloat(qtamax);
subtot = subtot - sconto;
qta = $("#qta_"+r).val().toEnglish();
// Se inserisco una quantità da evadere maggiore di quella rimanente, la imposto al massimo possibile
if(qta > qtamax){
qta = qtamax;
$('#qta_'+r).val(qta);
}
// Se tolgo la spunta della casella dell'evasione devo azzerare i conteggi
if(isNaN(qta) || !$('#checked_'+r).is(':checked')){
qta = 0;
}
$("#serial_"+r).selectClear();
$("#serial_"+r).select2("destroy");
$("#serial_"+r).data('maximum', qta);
start_superselect();
subtotale = (subtot * qta + iva * qta).toLocale();
$("#subtotale_"+r).html(subtotale+" &euro;");
$("#subtotaledettagli_"+r).html((subtot * qta).toLocale() + " + " + (iva * qta).toLocale());
ricalcola_totale();
}
function ricalcola_totale(){
tot_qta = 0;
r = 0;
totale = 0.00;
$('input[id*=qta_]').each( function(){
qta = $(this).val().toEnglish();
if( !$('#checked_'+r).is(':checked') || isNaN(qta) ){
qta = 0;
}
subtot = $("#subtot_"+r).val();
sconto = $("#sconto_"+r).val();
iva = $("#iva_"+r).val();
subtot = parseFloat(subtot);
sconto = parseFloat(sconto);
iva = parseFloat(iva);
subtot = subtot-sconto;
totale += subtot*qta+iva*qta;
r++;
tot_qta +=qta;
});
$('#totale').html( (totale.toLocale()) + " &euro;" );
if( tot_qta>0 )
$('#submit_btn').show();
else
$('#submit_btn').hide();
}
</script>
echo App::load('importa.php', $result, $options, true);

View File

@ -9,6 +9,8 @@ if ($module['name'] == 'Ordini cliente') {
$dir = 'uscita';
}
$_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
?><form action="" method="post" id="edit-form">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="update">
@ -104,7 +106,7 @@ if ($module['name'] == 'Ordini cliente') {
</div>
<!-- Fatturazione Elettronica PA-->
<div class="panel panel-primary <?php echo ($dir == 'entrata' && $record['tipo_anagrafica'] == 'Ente pubblico' or ($record['tipo_anagrafica']) == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel panel-primary <?php echo ($record['tipo_anagrafica'] == 'Ente pubblico' || $record['tipo_anagrafica'] == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Dati appalto'); ?></h3>
</div>

View File

@ -11,6 +11,7 @@ class Articolo extends Article
use RelationTrait;
protected $table = 'or_righe_ordini';
protected $serialRowID = 'ordine';
/**
* Crea un nuovo articolo collegato ad una ordine.

View File

@ -3,8 +3,6 @@
include_once __DIR__.'/../../core.php';
use Modules\Anagrafiche\Anagrafica;
use Modules\Fatture\Fattura;
use Modules\Fatture\Tipo as TipoFattura;
use Modules\Interventi\TipoSessione;
use Modules\Preventivi\Components\Articolo;
use Modules\Preventivi\Components\Riga;
@ -370,36 +368,6 @@ switch (post('op')) {
flash()->info(tr('Aggiunta nuova revisione!'));
break;
// Creazione fattura da preventivo
case 'fattura_da_preventivo':
$preventivo = Preventivo::find($id_record);
$tipo = TipoFattura::where('descrizione', 'Fattura immediata di vendita')->first();
$id_segment = $dbo->fetchOne('SELECT * FROM zz_segments WHERE id_module='.prepare($id_module)." AND predefined='1'")['id'];
$data = date('Y-m-d');
$fattura = Fattura::build($preventivo->anagrafica, $tipo, $data, $id_segment);
$fattura->idpagamento = $preventivo->idpagamento;
$id_conto = setting('Conto predefinito fatture di vendita');
$righe = $preventivo->getRighe();
foreach ($righe as $riga) {
$copia = $riga->copiaIn($fattura);
$copia->idconto = $id_conto;
if ($riga->isArticolo()) {
$copia->movimenta($copia->qta);
}
}
flash()->info(tr('Creata una nuova fattura!'));
$id_record = $fattura->id;
$id_module = Modules::get('Fatture di vendita')['id'];
break;
}
if (post('op') !== null && post('op') != 'update') {

View File

@ -11,24 +11,12 @@ switch ($resource) {
$filter[] = 'id='.prepare($element);
}
$where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']);
$where[] = 'co_preventivi.default_revision=1';
if (empty($elements)) {
$where[] = 'an_anagrafiche.idanagrafica='.prepare($superselect['idanagrafica']);
$where[] = 'co_preventivi.default_revision=1';
$stati = !empty($superselect['stati']) ? $superselect['stati'] : [
'In attesa di conferma',
'Accettato',
'In lavorazione',
'Concluso',
'In attesa di pagamento',
];
$desc = [];
foreach ($stati as $value) {
$desc[] = prepare($value);
}
$where[] = 'idstato IN (SELECT `id` FROM co_statipreventivi WHERE descrizione IN ('.implode(',', $desc).'))';
if (!empty($superselect['non_fatturato'])) {
$where[] = 'id NOT IN (SELECT idpreventivo FROM co_righe_documenti WHERE idpreventivo IS NOT NULL)';
$stato = !empty($superselect['stato']) ? $superselect['stato'] : 'fatturabile';
$where[] = 'idstato IN (SELECT `id` FROM co_staticontratti WHERE '.$stato.' = 1)';
}
if (!empty($search)) {

View File

@ -5,33 +5,31 @@ include_once __DIR__.'/../../core.php';
echo'
<button type="button" class="btn btn-primary" onclick="if( confirm(\'Duplicare questo preventivo?\') ){ $(\'#copia-preventivo\').submit(); }"> <i class="fa fa-copy"></i> '.tr('Duplica preventivo').'</button>';
if (!in_array($record['stato'], ['Bozza', 'Rifiutato', 'In attesa di conferma'])) {
$disabled = '';
} else {
$disabled = $record['fatturabile'] || $record['annullato'];
if (!$disabled) {
echo '
<button type="button" class="btn btn-warning" onclick="if(confirm(\'Vuoi creare un nuova revisione?\')){$(\'#crea-revisione\').submit();}"><i class="fa fa-edit"></i> '.tr('Crea nuova revisione...').'</button>';
$disabled = 'disabled';
}
// Creazione altri documenti
echo '
<div style="margin-left:4px;" class="dropdown pull-right" >
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" '.$disabled.' >
<i class="fa fa-magic"></i>&nbsp;'.tr('Crea').'...
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<div style="margin-left:4px;" class="dropdown pull-right">
<button class="btn btn-info dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true" '.($disabled ? '' : 'disabled').' >
<i class="fa fa-magic"></i>&nbsp;'.tr('Crea').'...
<span class="caret"></span>
</button>
<ul class="dropdown-menu dropdown-menu-right">
<li>
<a data-href="'.$rootdir.'/modules/ordini/crea_documento.php?id_module='.$id_module.'&id_record='.$id_record.'&documento=ordine" data-toggle="modal" data-title="'.tr('Crea ordine').'"><i class="fa fa-file-o"></i>&nbsp;'.tr('Ordine').'
</a>
<a class="'.($disabled ? '' : 'disabled').'" data-href="'.$structure->fileurl('crea_documento.php').'?id_module='.$id_module.'&id_record='.$id_record.'&documento=ordine" data-toggle="modal" data-title="'.tr('Crea ordine').'">
<i class="fa fa-file"></i>&nbsp;'.tr('Ordine').'
</a>
</li>
<li>
<a onclick="crea_fattura()"><i class="fa fa-file"></i>&nbsp;'.tr('Fattura').'
<a class="'.($disabled ? '' : 'disabled').'" data-href="'.$structure->fileurl('crea_documento.php').'?id_module='.$id_module.'&id_record='.$id_record.'&documento=fattura" data-toggle="modal" data-title="'.tr('Crea fattura').'">
<i class="fa fa-file"></i>&nbsp;'.tr('Fattura').'
</a>
</li>
</ul>
</div>';
@ -49,24 +47,3 @@ echo '
<input type="hidden" name="op" value="add_revision">
<input type="hidden" name="id_record" value="'.$id_record.'">
</form>';
// Crea fattura
echo '
<form action="" method="post" id="fattura-da-preventivo">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="op" value="fattura_da_preventivo">
<input type="hidden" name="id_record" value="'.$id_record.'">
</form>
<script>
function crea_fattura(){
swal({
title: "'.tr('Creare una fattura per questo preventivo?').'",
type: "warning",
showCancelButton: true,
confirmButtonText: "'.tr('Sì').'"
}).then(function (result) {
$("#fattura-da-preventivo").submit();
})
}
</script>';

View File

@ -0,0 +1,27 @@
<?php
include_once __DIR__.'/../../core.php';
$module = Modules::get($id_module);
$options = [
'op' => 'add_preventivo',
'id_importazione' => 'id_preventivo',
'final_module' => get('documento') == 'fattura' ? 'Fatture di vendita' : 'Ordini cliente',
'original_module' => $module['name'],
'sql' => [
'table' => 'co_preventivi',
'rows' => 'co_righe_preventivi',
'id_rows' => 'idpreventivo',
],
'button' => tr('Aggiungi'),
'dir' => 'entrata',
'create_document' => true,
];
$result = [
'id_record' => $id_record,
'id_documento' => get('iddocumento'),
];
echo App::load('importa.php', $result, $options, true);

View File

@ -119,7 +119,7 @@ $_SESSION['superselect']['idanagrafica'] = $record['idanagrafica'];
</div>
<!-- Fatturazione Elettronica -->
<div class="panel panel-primary <?php echo (($record['tipo_anagrafica']) == 'Ente pubblico' or ($record['tipo_anagrafica']) == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel panel-primary <?php echo ($record['tipo_anagrafica'] == 'Ente pubblico' || $record['tipo_anagrafica'] == 'Azienda') ? 'show' : 'hide'; ?>" >
<div class="panel-heading">
<h3 class="panel-title"><?php echo tr('Dati appalto'); ?></h3>
</div>

View File

@ -5,5 +5,11 @@ include_once __DIR__.'/../../core.php';
if (isset($id_record)) {
$preventivo = Modules\Preventivi\Preventivo::with('stato')->find($id_record);
$record = $dbo->fetchOne('SELECT *, (SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_preventivi.idanagrafica) AS tipo_anagrafica, (SELECT descrizione FROM co_statipreventivi WHERE id=idstato) AS stato FROM co_preventivi WHERE id='.prepare($id_record).Modules::getAdditionalsQuery($id_module));
$record = $dbo->fetchOne('SELECT *,
(SELECT tipo FROM an_anagrafiche WHERE idanagrafica = co_preventivi.idanagrafica) AS tipo_anagrafica,
(SELECT fatturabile FROM co_statipreventivi WHERE id=idstato) AS fatturabile,
(SELECT annullato FROM co_statipreventivi WHERE id=idstato) AS annullato,
(SELECT descrizione FROM co_statipreventivi WHERE id=idstato) AS stato
FROM co_preventivi
WHERE id='.prepare($id_record));
}

View File

@ -40,10 +40,11 @@ foreach ($rs as $r) {
// q.tà
echo '
<td class="text-right">';
<td class="text-center">';
if (empty($r['is_descrizione'])) {
echo '
'.Translator::numberToLocale($r['qta'], 'qta');
<big>'.Translator::numberToLocale($r['qta'] - $r['qta_evasa'], 'qta').'</big>
<br><small>('.tr('Q. iniziale').': '.Translator::numberToLocale($r['qta'], 'qta').')</small>';
}
echo '
</td>';

View File

@ -5,6 +5,7 @@ namespace Modules\Preventivi;
use Carbon\Carbon;
use Common\Document;
use Modules\Anagrafiche\Anagrafica;
use Modules\Interventi\Intervento;
use Modules\Interventi\TipoSessione;
use Traits\RecordTrait;
use Util\Generator;
@ -132,6 +133,11 @@ class Preventivo extends Document
return $this->hasOne(Components\Sconto::class, 'idpreventivo');
}
public function interventi()
{
return $this->hasMany(Intervento::class, 'id_preventivo');
}
// Metodi statici
/**

View File

@ -2,7 +2,7 @@
include_once __DIR__.'/../../core.php';
?><form action="<?php echo ROOTDIR; ?>/editor.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>" method="post" id="add-form">
?><form action="<?php echo ROOTDIR; ?>/controller.php?id_module=<?php echo Modules::get('Prima nota')['id']; ?>" method="post" id="add-form">
<input type="hidden" name="op" value="add">
<input type="hidden" name="backto" value="record-edit">
<input type="hidden" name="iddocumento" value="<?php echo get('iddocumento'); ?>">
@ -26,9 +26,14 @@ include_once __DIR__.'/../../core.php';
if ($tipo_doc == 'Nota di credito') {
$nota_credito = true;
$tipo_doc = 'nota di credito';
} elseif ($tipo_doc == 'Nota di debito') {
$tipo_doc = 'nota di debito';
} else {
$tipo_doc = 'fattura';
}
$descrizione = tr('_DOC_ numero _NUM_ del _DATE_ (_NAME_)', [
$descrizione = tr('Pag. _DOC_ num. _NUM_ del _DATE_ (_NAME_)', [
'_DOC_' => $tipo_doc,
'_NUM_' => $numero_doc,
'_DATE_' => Translator::dateToLocale($rs[0]['data']),
@ -242,7 +247,7 @@ include_once __DIR__.'/../../core.php';
<!-- PULSANTI -->
<div class="row">
<div class="col-md-12 text-right">
<button type='button' class="btn btn-primary" id='btn_crea_modello'><i class="fa fa-plus"></i> <?php echo tr('Aggiungi e crea modello'); ?></button>
<button type='button' class="btn btn-default" id='btn_crea_modello'><i class="fa fa-plus"></i> <?php echo tr('Aggiungi e crea modello'); ?></button>
<button type="submit" class="btn btn-primary" id='btn_submit'><i class="fa fa-plus"></i> <?php echo tr('Aggiungi'); ?></button>
</div>
</div>
@ -336,7 +341,7 @@ include_once __DIR__.'/../../core.php';
$('#bs-popup #modello_primanota').change(function(){
if ($(this).val()!=''){
$('#btn_crea_modello').html('<i class="fa fa-edit"></i> '+'<?php echo tr('Aggiungi e modifica modello'); ?>');
$('#bs-popup #idmastrino').val($(this).val());
@ -344,19 +349,19 @@ include_once __DIR__.'/../../core.php';
$('#btn_crea_modello').html('<i class="fa fa-plus"></i> '+'<?php echo tr('Aggiungi e crea modello'); ?>');
$('#bs-popup #idmastrino').val(0);
}
var idmastrino = $(this).val();
if(idmastrino!=''){
var causale = $(this).find('option:selected').text();
//aggiornava erroneamente anche la causale ed eventuale numero di fattura e data
<?php if (empty($iddocumento)) {
?>
$('#bs-popup #desc').val(causale);
<?php
} ?>
$.get('<?php echo $rootdir; ?>/ajax_complete.php?op=get_conti&idmastrino='+idmastrino, function(data){
var conti = data.split(',');
for(i=0;i<conti.length;i++){
@ -377,4 +382,3 @@ include_once __DIR__.'/../../core.php';
});
</script>
</form>

View File

@ -6,9 +6,8 @@ switch (filter('op')) {
case 'update':
$descrizione = filter('descrizione');
$percentuale = filter('percentuale');
$percentuale_imponibile = filter('percentuale_imponibile');
$percentuale_imponibile = filter('percentuale_imponibile');
if (isset($descrizione) && isset($percentuale) && isset($percentuale_imponibile)) {
if ($dbo->fetchNum('SELECT * FROM `co_ritenutaacconto` WHERE `descrizione`='.prepare($descrizione).' AND `id`!='.prepare($id_record)) == 0) {
$dbo->query('UPDATE `co_ritenutaacconto` SET `descrizione`='.prepare($descrizione).', `percentuale`='.prepare($percentuale).', `percentuale_imponibile`='.prepare($percentuale_imponibile).' WHERE `id`='.prepare($id_record));

View File

@ -51,4 +51,4 @@ if ($record['doc_associati'] == 0) {
<a class="btn btn-danger ask" data-backto="record-list">
<i class="fa fa-trash"></i> '.tr('Elimina').'
</a>';
}
}

Some files were not shown because too many files have changed in this diff Show More