import '../database/daos/ordini_dao.dart'; import '../database/daos/promozioni_dao.dart'; import '../database/daos/articoli_dao.dart'; import '../database/daos/sconti_dao.dart'; import '../database/database.dart'; class ApplicaPromoResult { final int tipoRisultato; final List righe; final List omaggi; static const int resultNone = 0; static const int resultRighe = 1; static const int resultOmaggi = 2; ApplicaPromoResult({ this.tipoRisultato = resultNone, this.righe = const [], this.omaggi = const [], }); } class ArticoloOmaggio { final int idArticolo; final String descrizione; final double quantita; final double quantitaDisponibile; final int progressivo; ArticoloOmaggio({ required this.idArticolo, required this.descrizione, required this.quantita, required this.quantitaDisponibile, required this.progressivo, }); } class PromoHandler { final OrdiniDao _ordiniDao; final PromozioniDao _promozioniDao; final ArticoliDao _articoliDao; final ScontiDao _scontiDao; PromoHandler(this._ordiniDao, this._promozioniDao, this._articoliDao, this._scontiDao); Future> getApplicablePromos(int idOrdine) async { final oggi = DateTime.now().toIso8601String(); return _promozioniDao.getActivePromos(oggi); } Future applicaPromo(int progressivo, int idOrdine) async { final promos = await _promozioniDao.getActivePromos(''); final promo = promos.where((p) => p.progressivo == progressivo).firstOrNull; if (promo == null) return ApplicaPromoResult(); final lines = await _ordiniDao.getOrderLines(idOrdine); final eligibleLines = lines.where((l) => (l.promozione == null || l.promozione == 0) && (l.rigaPromozione == null || l.rigaPromozione == 0) && (l.scontoMerce == null || l.scontoMerce == 0) ).toList(); switch (promo.tipoPromozione) { case 2: return _applicaTipo2(promo, eligibleLines, idOrdine); case 3: return _applicaTipo3(promo, eligibleLines, idOrdine); case 4: return _applicaTipo4(promo, eligibleLines, idOrdine); case 5: return _applicaTipo5(promo, eligibleLines, idOrdine); case 6: return _applicaTipo6(promo, eligibleLines, idOrdine); case 9: return _applicaTipo9(promo, eligibleLines, idOrdine); default: return ApplicaPromoResult(); } } Future _applicaTipo2(Promozione promo, List lines, int idOrdine) async { final promoArts = await _promozioniDao.getPromoArticoli(promo.progressivo); final newLines = []; for (final line in lines) { if (line.colli == null || line.colli! < (promo.limiteQta ?? 0)) continue; final isMatch = promoArts.any((a) => a.idArticolo == line.idArticolo); if (!isMatch) continue; final giftQty = promo.quantitaOmaggio ?? 1; newLines.add(RigaOrdine( idRigaOrdine: 0, idOrdine: idOrdine, idArticolo: promo.idArticoloOmaggio ?? line.idArticolo, quantita: giftQty, prezzoLordo: 0, prezzoNetto: 0, totale: 0, promozione: promo.progressivo, rigaPromozione: 1, colli: 0, )); } return ApplicaPromoResult( tipoRisultato: newLines.isEmpty ? ApplicaPromoResult.resultNone : ApplicaPromoResult.resultRighe, righe: newLines, ); } Future _applicaTipo3(Promozione promo, List lines, int idOrdine) async { final promoListini = await _promozioniDao.getPromoListini(promo.progressivo); final promoArts = await _promozioniDao.getPromoArticoli(promo.progressivo); final newLines = []; for (final line in lines) { if (line.colli == null || line.colli! < (promo.limiteQta ?? 0)) continue; final listinoMatch = promoListini.any((l) => l.idListino == line.idListino); if (!listinoMatch) continue; if (promoArts.isNotEmpty && !promoArts.any((a) => a.idArticolo == line.idArticolo)) continue; final giftQty = promo.quantitaOmaggio ?? 1; newLines.add(RigaOrdine( idRigaOrdine: 0, idOrdine: idOrdine, idArticolo: promo.idArticoloOmaggio ?? line.idArticolo, quantita: giftQty, prezzoLordo: 0, prezzoNetto: 0, totale: 0, promozione: promo.progressivo, rigaPromozione: 1, colli: 0, )); } return ApplicaPromoResult( tipoRisultato: newLines.isEmpty ? ApplicaPromoResult.resultNone : ApplicaPromoResult.resultRighe, righe: newLines, ); } Future _applicaTipo4(Promozione promo, List lines, int idOrdine) async { final totalColli = lines.fold(0.0, (sum, l) => sum + (l.colli ?? 0)); if (totalColli < (promo.limiteQta ?? 0)) return ApplicaPromoResult(); final omaggi = await _promozioniDao.getPromoOmaggi(promo.progressivo); final articoliOmaggio = []; for (final om in omaggi) { if (om.idArticolo == null) continue; articoliOmaggio.add(ArticoloOmaggio( idArticolo: om.idArticolo!, descrizione: 'Articolo ${om.idArticolo}', quantita: om.quantita ?? 1, quantitaDisponibile: om.quantita ?? 1, progressivo: promo.progressivo, )); } if (articoliOmaggio.length == 1) { final newLines = []; newLines.add(RigaOrdine( idRigaOrdine: 0, idOrdine: idOrdine, idArticolo: articoliOmaggio.first.idArticolo, quantita: articoliOmaggio.first.quantita, prezzoLordo: 0, prezzoNetto: 0, totale: 0, promozione: promo.progressivo, rigaPromozione: 1, colli: 0, )); return ApplicaPromoResult(tipoRisultato: ApplicaPromoResult.resultRighe, righe: newLines); } return ApplicaPromoResult( tipoRisultato: ApplicaPromoResult.resultOmaggi, omaggi: articoliOmaggio, ); } Future _applicaTipo5(Promozione promo, List lines, int idOrdine) async { final promoArts = await _promozioniDao.getPromoArticoli(promo.progressivo); final promoListini = await _promozioniDao.getPromoListini(promo.progressivo); final newLines = []; double totalColli = 0; final matchingLines = []; for (final line in lines) { bool match = true; if (promoArts.isNotEmpty && !promoArts.any((a) => a.idArticolo == line.idArticolo)) match = false; if (promoListini.isNotEmpty && !promoListini.any((l) => l.idListino == line.idListino)) match = false; if (match) { totalColli += (line.colli ?? 0); matchingLines.add(line); } } if (totalColli < (promo.limiteQta ?? 0)) return ApplicaPromoResult(); final giftMultiplier = (totalColli / (promo.limiteQta ?? 1)).floor(); final totalGiftQty = (giftMultiplier * (promo.quantitaOmaggio ?? 1)).toDouble(); if (promo.idArticoloOmaggio != null) { newLines.add(RigaOrdine( idRigaOrdine: 0, idOrdine: idOrdine, idArticolo: promo.idArticoloOmaggio!, quantita: totalGiftQty, prezzoLordo: 0, prezzoNetto: 0, totale: 0, promozione: promo.progressivo, rigaPromozione: 1, colli: 0, )); } return ApplicaPromoResult( tipoRisultato: newLines.isEmpty ? ApplicaPromoResult.resultNone : ApplicaPromoResult.resultRighe, righe: newLines, ); } Future _applicaTipo6(Promozione promo, List lines, int idOrdine) async { final totalImporto = lines.fold(0.0, (sum, l) => sum + (l.totale ?? 0)); if (totalImporto < (promo.limiteImporto ?? 0)) return ApplicaPromoResult(); final giftMultiplier = (totalImporto / (promo.limiteImporto ?? 1)).floor(); final totalGiftQty = (giftMultiplier * (promo.quantitaOmaggio ?? 1)).toDouble(); final newLines = []; if (promo.idArticoloOmaggio != null) { newLines.add(RigaOrdine( idRigaOrdine: 0, idOrdine: idOrdine, idArticolo: promo.idArticoloOmaggio!, quantita: totalGiftQty, prezzoLordo: 0, prezzoNetto: 0, totale: 0, promozione: promo.progressivo, rigaPromozione: 1, colli: 0, )); } return ApplicaPromoResult( tipoRisultato: newLines.isEmpty ? ApplicaPromoResult.resultNone : ApplicaPromoResult.resultRighe, righe: newLines, ); } Future _applicaTipo9(Promozione promo, List lines, int idOrdine) async { final promoArts = await _promozioniDao.getPromoArticoli(promo.progressivo); final promoListini = await _promozioniDao.getPromoListini(promo.progressivo); final newLines = []; final modifiedLines = []; for (final line in lines) { if (line.quantita == null || line.quantita! < (promo.limiteQta ?? 0)) continue; bool match = true; if (promoArts.isNotEmpty && !promoArts.any((a) => a.idArticolo == line.idArticolo)) match = false; if (promoListini.isNotEmpty && !promoListini.any((l) => l.idListino == line.idListino)) match = false; if (!match) continue; final freeQty = ((line.quantita! / (promo.limiteQta ?? 1)).floor() * (promo.quantitaOmaggio ?? 1)).toDouble(); if (freeQty <= 0) continue; newLines.add(RigaOrdine( idRigaOrdine: 0, idOrdine: idOrdine, idArticolo: line.idArticolo, idListino: line.idListino, quantita: freeQty, prezzoLordo: 0, prezzoNetto: 0, totale: 0, promozione: promo.progressivo, rigaPromozione: 1, colli: line.colli, )); } return ApplicaPromoResult( tipoRisultato: newLines.isEmpty ? ApplicaPromoResult.resultNone : ApplicaPromoResult.resultRighe, righe: newLines, ); } Future selezionaOmaggio(int progressivo, int idArticoloScelto, int idOrdine) async { final promo = await _promozioniDao.getActivePromos(''); final p = promo.where((x) => x.progressivo == progressivo).firstOrNull; if (p == null) return ApplicaPromoResult(); final newLines = [ RigaOrdine( idRigaOrdine: 0, idOrdine: idOrdine, idArticolo: idArticoloScelto, quantita: p.quantitaOmaggio ?? 1, prezzoLordo: 0, prezzoNetto: 0, totale: 0, promozione: progressivo, rigaPromozione: 1, colli: 0, ), ]; return ApplicaPromoResult(tipoRisultato: ApplicaPromoResult.resultRighe, righe: newLines); } }