diff --git a/Controller/EditRegularizacionImpuesto.php b/Controller/EditRegularizacionImpuesto.php index 5f21acd..317d376 100644 --- a/Controller/EditRegularizacionImpuesto.php +++ b/Controller/EditRegularizacionImpuesto.php @@ -22,15 +22,16 @@ use FacturaScripts\Core\Base\DataBase\DataBaseWhere; use FacturaScripts\Core\DataSrc\Impuestos; use FacturaScripts\Core\DataSrc\Series; +use FacturaScripts\Core\KernelException; use FacturaScripts\Core\Lib\ExtendedController\BaseView; use FacturaScripts\Core\Lib\ExtendedController\EditController; -use FacturaScripts\Core\Model\Asiento; use FacturaScripts\Core\Tools; use FacturaScripts\Dinamic\Lib\Accounting\VatRegularizationToAccounting; use FacturaScripts\Dinamic\Lib\SubAccountTools; use FacturaScripts\Dinamic\Model\Join\PartidaImpuestoResumen; -use FacturaScripts\Dinamic\Model\Partida; use FacturaScripts\Dinamic\Model\RegularizacionImpuesto; +use FacturaScripts\Plugins\Modelo303\Lib\Modelo303Calculator; +use FacturaScripts\Plugins\Modelo303\Lib\Modelo303Data; /** * Controller to list the items in the RegularizacionImpuesto model @@ -50,8 +51,7 @@ class EditRegularizacionImpuesto extends EditController /** @var float */ public $total; - /** @var array */ - public array $modelo303 = []; + public Modelo303Data $modelo303; public function getModelClassName(): string { @@ -209,163 +209,17 @@ protected function getListPartidaImpuesto(BaseView $view, int $group): void } } + /** + * @throws KernelException + */ protected function getListPartidaImpuestoResumen(BaseView $view): void { - $impuestos = Impuestos::all(); - - // obtenemos los codigos de subcuentas de los impuestos - $subcuentas = array_values(array_unique(array_filter(array_merge( - array_column($impuestos, 'codsubcuentarep'), - array_column($impuestos, 'codsubcuentasop'), - )))); - - // Obtenemos los asientos para poder filtrar - // por fecha. Asi nos aseguramos que se filtra - // primero por fecha de devengo y si no existe - // por fecha de factura - $asientos = Asiento::all([ - new DataBaseWhere('codejercicio', $this->getModel()->codejercicio), - new DataBaseWhere('fecha', $this->getModel()->fechainicio, '>='), - new DataBaseWhere('fecha', $this->getModel()->fechafin, '<'), - ], [], 0, 0); - $idsAsientos = array_unique(array_column($asientos, Asiento::primaryColumn())); - - if(empty($idsAsientos)) { - Tools::log()->warning('accounting-entry-not-found'); - return; - } - - $partidas = Partida::all([ - new DataBaseWhere('idasiento', $idsAsientos, 'IN'), - new DataBaseWhere('codsubcuenta', $subcuentas, 'IN') - ], [], 0, 0); - - // agrupamos por subcuenta - $partidasAgrupadas = []; - foreach ($partidas as $partida) { - $partidasAgrupadas[$partida->codsubcuenta][] = $partida; - } - - // inicializamos el modelo303 - $this->modelo303 = []; - for ($i = 0; $i <= 200; $i++) { - $this->modelo303[sprintf('%02d', $i)] = 0.00; - } - - // set default values - $this->modelo303['02'] = 4.00; - $this->modelo303['05'] = 10.00; - $this->modelo303['08'] = 21.00; - $this->modelo303['157'] = 1.75; - $this->modelo303['169'] = 0.5; - $this->modelo303['20'] = 1.4; - $this->modelo303['23'] = 5.2; - - // obtenemos los códigos de subcuentas agrupados según tipo iva - // esto lo hacemos por si existen varios impuestos - // del mismo iva y distintas subcuentas - $subcuentasSegunIVA = []; - foreach ($impuestos as $impuesto) { - $subcuentasSegunIVA[$impuesto->iva]['repercutido'][] = $impuesto->codsubcuentarep; - $subcuentasSegunIVA[$impuesto->iva]['soportado'][] = $impuesto->codsubcuentasop; - } - - // obtenemos los codigos de subcuentas agrupados según tipo recargo - // esto lo hacemos por si existen varios impuestos - // del mismo recargo y distintas subcuentas - $subcuentasSegunRecargo = []; - foreach ($impuestos as $impuesto) { - $subcuentasSegunRecargo[$impuesto->recargo]['repercutido'][] = $impuesto->codsubcuentarepre; - $subcuentasSegunRecargo[$impuesto->recargo]['soportado'][] = $impuesto->codsubcuentasopre; - } - - foreach ($partidasAgrupadas as $subcuenta => $movimientos) { - foreach ($movimientos as $mov) { - // IVA 4% - if (in_array($subcuenta, $subcuentasSegunIVA[4]['repercutido'])) { - $this->modelo303['01'] += $mov->baseimponible; - $this->modelo303['03'] += $mov->haber; - } - - // IVA 10% - if (in_array($subcuenta, $subcuentasSegunIVA[10]['repercutido'])) { - $this->modelo303['04'] += $mov->baseimponible; - $this->modelo303['06'] += $mov->haber; - } - - // IVA 21% - if (in_array($subcuenta, $subcuentasSegunIVA[21]['repercutido'])) { - $this->modelo303['07'] += $mov->baseimponible; - $this->modelo303['09'] += $mov->haber; - } - - // IVA 0% - if (in_array($subcuenta, $subcuentasSegunIVA[0]['repercutido'])) { - $this->modelo303['150'] += $mov->baseimponible; - $this->modelo303['152'] += $mov->haber; - } - - // RECARGO 1.75% - if (in_array($subcuenta, $subcuentasSegunRecargo[1.75]['repercutido'])) { - $this->modelo303['156'] += $mov->baseimponible; - $this->modelo303['158'] += $mov->haber; - } - - // RECARGO 0.5% - if (in_array($subcuenta, $subcuentasSegunRecargo[0.5]['repercutido'])) { - $this->modelo303['168'] += $mov->baseimponible; - $this->modelo303['170'] += $mov->haber; - } - - // RECARGO 1.4% - if (in_array($subcuenta, $subcuentasSegunRecargo[1.4]['repercutido'])) { - $this->modelo303['19'] += $mov->baseimponible; - $this->modelo303['21'] += $mov->haber; - } - - // RECARGO 5.2% - if (in_array($subcuenta, $subcuentasSegunRecargo[5.2]['repercutido'])) { - $this->modelo303['22'] += $mov->baseimponible; - $this->modelo303['24'] += $mov->haber; - } - } - } - - // Total cuota devengada - $this->modelo303['27'] = $this->modelo303['152'] + $this->modelo303['167'] + $this->modelo303['03'] + $this->modelo303['155'] + $this->modelo303['06'] + $this->modelo303['09'] + $this->modelo303['11'] + $this->modelo303['13'] + $this->modelo303['15'] + $this->modelo303['158'] + $this->modelo303['170'] + $this->modelo303['18'] + $this->modelo303['21'] + $this->modelo303['24'] + $this->modelo303['26']; - - /** - * IVA DEDUCIBLE - */ - - // Por cuotas soportadas en operaciones interiores corrientes - foreach ($partidasAgrupadas as $subcuenta => $movimientos) { - foreach ($movimientos as $mov) { - // IVA 4% - if (in_array($subcuenta, $subcuentasSegunIVA[4]['soportado'])) { - $this->modelo303['28'] += $mov->baseimponible; - $this->modelo303['29'] += $mov->debe; - } - - // IVA 10% - if (in_array($subcuenta, $subcuentasSegunIVA[10]['soportado'])) { - $this->modelo303['28'] += $mov->baseimponible; - $this->modelo303['29'] += $mov->debe; - } - - // IVA 21% - if (in_array($subcuenta, $subcuentasSegunIVA[21]['soportado'])) { - $this->modelo303['28'] += $mov->baseimponible; - $this->modelo303['29'] += $mov->debe; - } - } - } - - // Total a deducir - $this->modelo303['45'] = $this->modelo303['29'] + $this->modelo303['31'] + $this->modelo303['33'] + $this->modelo303['35'] + $this->modelo303['37'] + $this->modelo303['39'] + $this->modelo303['41'] + $this->modelo303['42'] + $this->modelo303['43'] + $this->modelo303['44']; - - // Resultado régimen general - $this->modelo303['46'] = $this->modelo303['27'] - $this->modelo303['45']; + // Calculamos casillas del modelo 303 + $this->modelo303 = Modelo303Calculator::calculate( + $this->getModel()->codejercicio, + $this->getModel()->fechainicio, + $this->getModel()->fechafin, + ); } /** diff --git a/Lib/AccountingItems.php b/Lib/AccountingItems.php new file mode 100644 index 0000000..dafd1a2 --- /dev/null +++ b/Lib/AccountingItems.php @@ -0,0 +1,51 @@ +='), + new DataBaseWhere('fecha', $fechafin, '<'), + ], [], 0, 0); + $idsAsientos = array_unique(array_column($asientos, Asiento::primaryColumn())); + + if(empty($idsAsientos)) { + Tools::log()->warning('accounting-entry-not-found'); + return []; + } + + $partidas = Partida::all([ + new DataBaseWhere('idasiento', $idsAsientos, 'IN'), + new DataBaseWhere('codsubcuenta', $subcuentas, 'IN') + ], [], 0, 0); + + $partidasAgrupadas = []; + foreach ($partidas as $partida) { + $partidasAgrupadas[$partida->codsubcuenta][] = $partida; + } + + return $partidasAgrupadas; + } +} \ No newline at end of file diff --git a/Lib/Modelo303Calculator.php b/Lib/Modelo303Calculator.php new file mode 100644 index 0000000..2ded2a1 --- /dev/null +++ b/Lib/Modelo303Calculator.php @@ -0,0 +1,199 @@ + $movimientos) { + foreach ($movimientos as $mov) { + // IVA 4% + if (in_array($subcuenta, $subcuentasSegunIVA[4]['repercutido'])) { + $modelo303->add('01', $mov->baseimponible); + $modelo303->add('03', $mov->haber); + } + + // IVA 10% + if (in_array($subcuenta, $subcuentasSegunIVA[10]['repercutido'])) { + $modelo303->add('04', $mov->baseimponible); + $modelo303->add('06', $mov->haber); + } + + // IVA 21% + if (in_array($subcuenta, $subcuentasSegunIVA[21]['repercutido'])) { + $modelo303->add('07', $mov->baseimponible); + $modelo303->add('09', $mov->haber); + } + + // IVA 0% + if (in_array($subcuenta, $subcuentasSegunIVA[0]['repercutido'])) { + $modelo303->add('150', $mov->baseimponible); + $modelo303->add('152', $mov->haber); + } + + // RECARGO 1.75% + if (in_array($subcuenta, $subcuentasSegunRecargo[1.75]['repercutido'])) { + $modelo303->add('156', $mov->baseimponible); + $modelo303->add('158', $mov->haber); + } + + // RECARGO 0.5% + if (in_array($subcuenta, $subcuentasSegunRecargo[0.5]['repercutido'])) { + $modelo303->add('168', $mov->baseimponible); + $modelo303->add('170', $mov->haber); + } + + // RECARGO 1.4% + if (in_array($subcuenta, $subcuentasSegunRecargo[1.4]['repercutido'])) { + $modelo303->add('19', $mov->baseimponible); + $modelo303->add('21', $mov->haber); + } + + // RECARGO 5.2% + if (in_array($subcuenta, $subcuentasSegunRecargo[5.2]['repercutido'])) { + $modelo303->add('22', $mov->baseimponible); + $modelo303->add('24', $mov->haber); + } + } + } + + // Total cuota devengada + $modelo303->set('27', $modelo303->get('152') + $modelo303->get('167') + $modelo303->get('03') + $modelo303->get('155') + $modelo303->get('06') + $modelo303->get('09') + $modelo303->get('11') + $modelo303->get('13') + $modelo303->get('15') + $modelo303->get('158') + $modelo303->get('170') + $modelo303->get('18') + $modelo303->get('21') + $modelo303->get('24') + $modelo303->get('26')); + + /** + * IVA DEDUCIBLE + */ + // Por cuotas soportadas en operaciones interiores corrientes + foreach ($partidasAgrupadas as $subcuenta => $movimientos) { + foreach ($movimientos as $mov) { + // IVA 4% + if (in_array($subcuenta, $subcuentasSegunIVA[4]['soportado'])) { + $modelo303->add('28', $mov->baseimponible); + $modelo303->add('29', $mov->debe); + } + + // IVA 10% + if (in_array($subcuenta, $subcuentasSegunIVA[10]['soportado'])) { + $modelo303->add('28', $mov->baseimponible); + $modelo303->add('29', $mov->debe); + } + + // IVA 21% + if (in_array($subcuenta, $subcuentasSegunIVA[21]['soportado'])) { + $modelo303->add('28', $mov->baseimponible); + $modelo303->add('29', $mov->debe); + } + } + } + + // Total a deducir + $modelo303->set('45', $modelo303->get('29') + $modelo303->get('31') + $modelo303->get('33') + $modelo303->get('35') + $modelo303->get('37') + $modelo303->get('39') + $modelo303->get('41') + $modelo303->get('42') + $modelo303->get('43') + $modelo303->get('44')); + + // Resultado régimen general + $modelo303->set('46', $modelo303->get('27') - $modelo303->get('45')); + + // Información adicional + // Ventas intracomunitarias + $modelo303->set('59', self::getNetoFacturasVentasIntra($codejercicio, $fechainicio, $fechafin)); + + // Compras intracomunitarias + $totalesFacturasComprasIntra = self::getTotalesFacturasComprasIntra($codejercicio, $fechainicio, $fechafin); + $baseFacturasComprasIntra = $totalesFacturasComprasIntra['base']; + $cuotaFacturasComprasIntra = $totalesFacturasComprasIntra['cuota']; + + $modelo303->set('10', $baseFacturasComprasIntra); + $modelo303->set('11', $cuotaFacturasComprasIntra); + + return $modelo303; + } + + /** + * obtenemos los códigos de subcuentas agrupados según tipo iva + * esto lo hacemos por si existen varios impuestos + * del mismo iva y distintas subcuentas + * + * @param array $impuestos + * + * @return array + */ + public static function getSubAccountCodesByTax(array $impuestos): array + { + $subcuentasSegunIVA = []; + foreach ($impuestos as $impuesto) { + $subcuentasSegunIVA[$impuesto->iva]['repercutido'][] = $impuesto->codsubcuentarep; + $subcuentasSegunIVA[$impuesto->iva]['soportado'][] = $impuesto->codsubcuentasop; + } + return $subcuentasSegunIVA; + } + + /** + * obtenemos los codigos de subcuentas agrupados según tipo recargo + * esto lo hacemos por si existen varios impuestos + * del mismo recargo y distintas subcuentas + * + * @param array $impuestos + * + * @return array + */ + public static function getSubAccountCodesBySurchargeType(array $impuestos): array + { + $subcuentasSegunRecargo = []; + foreach ($impuestos as $impuesto) { + $subcuentasSegunRecargo[$impuesto->recargo]['repercutido'][] = $impuesto->codsubcuentarepre; + $subcuentasSegunRecargo[$impuesto->recargo]['soportado'][] = $impuesto->codsubcuentasopre; + } + return $subcuentasSegunRecargo; + } + + /** + * @throws KernelException + */ + private static function getNetoFacturasVentasIntra(string $codejercicio, string $fechainicio, string $fechafin) + { + $dataBase = new DataBase(); + + $sql = "SELECT SUM(neto) AS neto FROM facturascli "; + $sql .= "WHERE codejercicio = " . $dataBase->var2str($codejercicio) . " AND "; + $sql .= "COALESCE(fechadevengo, fecha) >= " . $dataBase->var2str($fechainicio) . " AND "; + $sql .= "COALESCE(fechadevengo, fecha) < " . $dataBase->var2str($fechafin) . " AND "; + $sql .= "operacion = " . $dataBase->var2str(InvoiceOperation::INTRA_COMMUNITY) . ";"; + + return $dataBase->select($sql)[0]['neto']; + } + + /** + * @throws KernelException + */ + private static function getTotalesFacturasComprasIntra(string $codejercicio, string $fechainicio, string $fechafin) + { + $dataBase = new DataBase(); + + $sql = "SELECT SUM(neto) AS base, SUM(totaliva) AS cuota FROM facturasprov "; + $sql .= "WHERE codejercicio = " . $dataBase->var2str($codejercicio) . " AND "; + $sql .= "COALESCE(fechadevengo, fecha) >= " . $dataBase->var2str($fechainicio) . " AND "; + $sql .= "COALESCE(fechadevengo, fecha) < " . $dataBase->var2str($fechafin) . " AND "; + $sql .= "operacion = " . $dataBase->var2str(InvoiceOperation::INTRA_COMMUNITY) . ";"; + + return $dataBase->select($sql)[0]; + } +} \ No newline at end of file diff --git a/Lib/Modelo303Data.php b/Lib/Modelo303Data.php new file mode 100644 index 0000000..04cb9ab --- /dev/null +++ b/Lib/Modelo303Data.php @@ -0,0 +1,53 @@ + 4.00, + '05' => 10.00, + '08' => 21.00, + '157' => 1.75, + '169' => 0.5, + '20' => 1.4, + '23' => 5.2 + ]; + + public function __construct() + { + $this->initialize(); + } + + private function initialize(): void + { + for ($i = 0; $i <= 200; $i++) { + $this->data[sprintf('%02d', $i)] = 0.00; + } + + foreach (self::DEFAULT_RATES as $key => $rate) { + $this->data[$key] = $rate; + } + } + + public function get(string $key): float + { + return $this->data[$key] ?? 0.00; + } + + public function set(string $key, float $value): void + { + $this->data[$key] = $value; + } + + public function add(string $key, float $value): void + { + $this->data[$key] = ($this->data[$key] ?? 0.00) + $value; + } + + public function toArray(): array + { + return $this->data; + } +} diff --git a/View/Modelo303.html.twig b/View/Modelo303.html.twig index 7ea7a34..ac61555 100644 --- a/View/Modelo303.html.twig +++ b/View/Modelo303.html.twig @@ -1,3 +1,4 @@ +{% set modelo303 = fsc.modelo303.toArray() %}