#include "777lib.h" /////////////////////////////////////////////////////////// // TTracciato770 /////////////////////////////////////////////////////////// void TTracciato770::add_field(const char* name, M770FieldType type, int pos, int len, int fldno) { switch (type) { case AN: break; case CB: CHECKD(len == 1, "Booleano di lunghezza sospetta ", len); // type = NU; break; case CF: CHECKD(len == 16, "Codice fiscale di lunghezza sospetta ", len); type = AN; break; case CN: CHECKD(len == 11, "Codice fiscale numerico di lunghezza sospetta ", len); type = NU; break; case DA: CHECKD(len == 6, "Mese+Anno di lunghezza sospetta ", len); type = NU; break; case DT: CHECKD(len == 8, "Data di lunghezza sospetta ", len); type = NU; break; case NU: break; case PN: case PR: CHECKD(len == 2, "provincia di lunghezza sospetta ", len); type = AN; break; default: CHECK(false, "tipo campo sospetto"); break; } TField770* info = new TField770; info->_desc = name; info->_type = type; info->_pos = pos; info->_len = len; if (fldno <= 0) fldno = _fields.add(info)+1; else _fields.add(info, fldno-1); } const TField770& TTracciato770::field(int pos) const { TField770* info = (TField770*)_fields.objptr(pos-1); #ifdef DBG if (info == NULL) fatal_box("Non esiste il campo %d sul tipo record %c", pos, _tipo); #endif return *info; } void TTracciato770::auto_fill(TString& buffer) const { buffer.fill(' ', TOTAL_SIZE); char* ptr = buffer.get_buffer(); for (int f = _fields.last(); f >= 0; f = _fields.pred(f)) { const TField770& info = (const TField770&)_fields[f]; if (info._type == NU || info._type == CB || info._type == DA || info._type == DT || info._type == CN) memset(ptr + info._pos - 1, '0', info._len); } buffer[0] = _tipo; buffer.overwrite("A\r\n", TOTAL_SIZE-3); } TTracciato770::TTracciato770(char tipo) : _tipo(tipo) { if (strchr("ABEFHJZ", tipo) == NULL) NFCHECK("Tipo record non valido: %c", tipo); add_field("Tipo record", AN, 1, 1); // 1 if (tipo == 'A') { add_filler(2, 14); // 2 add_field("Codice fornitura", AN, 16, 5); // 3 add_field("Tipo fornitore", NU, 21, 2); // 4 add_field("Codice fiscale del fornitore", CF, 23, 16); add_filler(39, 483); // Dichiarazione su pił invii add_field("Progressivo dell'invio", NU, 522, 4); // 7 add_field("Numero totale degli invii", NU, 526, 4); } else if (tipo == 'B') { add_field("Codice fiscale dichiarante", CF, 2, 16); // 2 add_field("Progressivo modulo", NU, 18, 8); add_filler( 26, 3); add_filler( 29,25); add_field("Spazio a disposizione", AN, 54, 20); add_field("CF del produttore del software", CF, 74, 16); // 7 add_field("Flag conferma", CB, 90, 1); // Tipo di dichiarazione add_field("Dichiarazione correttiva nei termini", CB, 91, 1); // 9 add_field("Dichiarazione correttiva parziale", CB, 92, 1); add_field("Dichiarazione integrativa", CB, 93, 1); add_field("Eventi eccezzziunali veramente", NU, 94, 1); // 12 // Dati del contribuente add_field("Cognome", AN, 95, 24); // 13 add_field("Nome", AN,119, 20); add_field("Denominazione (Alternativo a 25 e 26)",AN,139, 60); add_filler(199,11); add_filler(210, 1); add_filler(211, 1); add_field("Codice Attivitą", NU, 212, 6); // 19 add_field("Indirizzo E-mail", AN, 218,100); add_field("Telefono o FAX", AN, 318, 12); add_filler(330, 12); add_field("Comune di nascita", AN, 342, 40, 23); // 23 add_field("Provincia di nascita", AN, 382, 2); add_field("Data di nascita", DT, 384, 8); add_field("Sesso", AN, 392, 1); add_field("Comune di residenza", AN, 393, 40, 27); // 27 add_field("Provincia residenza", AN, 433, 2); add_field("C.a.p. residenza", NU, 435, 5); add_field("Codice comune", AN, 440, 4); add_field("Indirizzo", AN, 444, 35); add_field("Data variazione", DT, 479, 8); add_field("Natura giuridica", NU, 487, 2, 33); // 33 add_field("Data variazione sede legale", DA, 489, 6); add_field("Comune della sede legale", AN, 495,40); add_field("Sigla della provincia sede legale", PR, 535, 2); add_field("CAP del comune della sede legale", NU, 537, 5); add_field("Codice comune", AN, 542, 4); add_field("Indirizzo della sede legale", AN, 546,35); add_field("Data variazione domicilio fiscale", NU, 581, 6); // 40 add_field("Comune del domicilio fiscale", AN, 587,40); add_field("Provincia del domicilio fiscale", PR, 627, 2); add_field("CAP del domicilio fiscale", NU, 629, 5); add_field("Codice comune", AN, 634, 4); add_field("Indirizzo del domicilio fiscale", AN, 638,35); add_field("Stato", NU, 673, 1); add_field("Situazione", NU, 674, 1); add_field("Dicastero di appartenenza", CN, 675,11); add_field("Redazione della dichiarazione", NU, 797, 1, 75); // 75 add_field("Numero comunicaz. lavoro dipendente", NU, 798, 8); add_field("Numero comunicaz. lavoro autonomo", NU, 806, 8); add_field("Casella prospetto SS", CB, 814, 1); // 78 add_field("Casella prospetto ST", CB, 815, 1); add_field("Casella prospetto SV", CB, 816, 1); add_field("Casella prospetto SX", CB, 817, 1); // 81 add_field("Casella prospetto SY", CB, 818, 1); add_field("Presenza 770 ordinario " THIS_YEAR, CB, 819, 1); add_field("Codice fiscale parte restante", CF, 820,16); add_field("Protocollo telematico", NU, 836,17); // 85 add_field("Progressivo telematico", NU, 853, 6); // dichiarazioni integrative o parziali add_field("Casella prospetto SS", CB, 859, 1); // 87 add_field("Casella prospetto ST", CB, 860, 1); add_field("Casella prospetto SV", CB, 861, 1); add_field("Casella prospetto SX", CB, 862, 1); add_field("Casella prospetto SY", CB, 863, 1); add_field("Numero comunicaz. lavoro dipendente", NU, 864, 8); add_field("Numero comunicaz. lavoro autonomo", NU, 872, 8); // 93 add_field("Firma del dichiarante", CB, 880, 1, 94); // 94 add_field("Codice fiscale", CF, 881,16); add_field("Soggetto", NU, 897, 1); add_field("Firma", CB, 898, 1); // 97 add_field("Codice fiscale", CF, 899,16); add_field("Soggetto", NU, 915, 1); add_field("Firma", CB, 916, 1); // 100 add_field("Codice fiscale", CF, 917,16); add_field("Soggetto", NU, 933, 1); add_field("Firma", CB, 934, 1); // 103 add_field("Codice fiscale", CF, 935,16); add_field("Soggetto", NU, 951, 1); add_field("Firma", CB, 952, 1); // 106 add_field("Codice fiscale", CF, 953,16); add_field("Soggetto", NU, 969, 1); add_field("Firma", CB, 970, 1); // 109 add_field("Non trasmissione ST, SV e/o SX", NU, 971, 1); add_field("Casella Attestazione", CB, 972, 1); add_field("Situazioni particolari", NU,1180,2, 116); // 116 add_field("Codice fiscale del rappresentante", CF,1396,16,126); // 126 add_field("Codice carica del rappresentante", NU,1412, 2); add_field("Data carica del rappresentante", DT,1414, 8); add_field("Cognome", AN,1493,24, 131); // 131 add_field("Nome", AN,1517,20); add_field("Sesso", AN,1537, 1); add_field("Data di nascita rappresentante", DT,1538, 8); add_field("Comune di nascita", AN,1546,40); // 135 add_field("Provincia di nascita", PN,1586, 2); add_field("Codice stato estero", NU,1588, 3); // 137 add_field("Stato federato, provincia, contea", AN,1591,24); add_field("Localitą di residenza", AN,1615,24); add_field("Indirizzo estero", AN,1639,35); // 140 add_field("Telefono cellulare rappresentante", AN,1674,12); add_field("Data apertura fallimento", DT,1686, 8); // 142 add_field("Codice fiscale societa o dichiarante", NU,1694,11); add_field("Invio avviso telematico", CB,1715, 1, 147); // 147 add_field("Ricezione avviso telematico", CB,1716, 1); add_field("Codice fiscale intermediario", CF,1717,16); add_field("Numero iscrizione C.A.F.", NU,1733, 5); add_field("Impegno a trasmettere la dichiaraz.", NU,1738, 1); // 151 add_field("Data dell'impegno", DT,1739, 8); add_field("Firma dell'intermediario", CB,1747, 1); add_field("Codice fiscale responsabile C.A.F.", CF,1748,16); add_field("Codice fiscale C.A.F.", CN,1764,11); add_field("Codice fiscale professionista", CF,1775,16); // 156 add_field("Firma", CB,1791, 1); } else if (tipo == 'E' || tipo == 'F') { add_field("Codice fiscale del dichiarante", CF, 2, 16); // 2 add_field("Progressivo modulo", NU, 18, 8); add_field("Spazio a disposizione", AN, 26, 3); add_field("Tipo operazione", AN, 29, 1); add_filler(30, 24); add_field("Spazio a disposizione", AN, 54, 20); add_field("Identificativo produttore software", AN, 74, 16); // 8 } else if (tipo == 'H') { add_field("Codice fiscale del dichiarante", CF, 2, 16); // 2 add_field("Progressivo comunicazione", NU, 18, 8); add_field("Spazio a disposizione", AN, 26, 3); add_field("Tipo operazione", AN, 29, 1); add_field("Codice fiscale del percipiente", AN, 30, 16); // 6 add_filler(46, 8); add_field("Spazio a disposizione", AN, 54, 20); add_field("Identificativo produttore software", AN, 74, 16); // 9 } else if (tipo == 'J') { add_field("Codice fiscale del dichiarante", CF, 2, 16); // 2 add_field("Progressivo modulo", NU, 18, 8); add_field("Spazio a disposizione", AN, 26, 3); add_field("Tipo operazione", AN, 29, 1); add_filler(30, 24); add_field("Spazio a disposizione", AN, 54, 20); add_field("Identificativo produttore software", AN, 74, 16); // 8 } else if (tipo == 'Z') { add_filler(2, 14); add_field("Numero record di tipo 'B'", NU, 16, 9, 3); // 3 add_field("Numero record di tipo 'C'", NU, 25, 9, 4); add_field("Numero record di tipo 'D'", NU, 34, 9, 5); add_field("Numero record di tipo 'G'", NU, 43, 9, 6); add_field("Numero record di tipo 'H'", NU, 52, 9, 7); add_field("Numero record di tipo 'L'", NU, 61, 9, 8); add_filler(70, 9); add_filler(79, 9); add_filler(88, 1810); } } TTracciato770::~TTracciato770() { } /////////////////////////////////////////////////////////// // TTracciati770 /////////////////////////////////////////////////////////// class TTracciati770 : public TObject { TArray _trc; public: const TTracciato770& tracciato(char tipo); void destroy(); TTracciati770(); virtual ~TTracciati770(); } _trc770; const TTracciato770& TTracciati770::tracciato(char tipo) { CHECK(tipo >= 'A' && tipo <= 'Z', "Tipo record non valido"); const int pos = tipo - 'A'; TTracciato770* trc = (TTracciato770*)_trc.objptr(pos); if (trc == NULL) { trc = new TTracciato770(tipo); _trc.add(trc, pos); } return *trc; } void TTracciati770::destroy() { _trc.destroy(); } TTracciati770::TTracciati770() { } TTracciati770::~TTracciati770() { destroy(); // Non viene mai chiamato! } /////////////////////////////////////////////////////////// // TRecord770 /////////////////////////////////////////////////////////// const TTracciato770& TRecord770::tracciato() const { return _trc770.tracciato(tipo_record()); } void TRecord770::print_on(ostream& outs) const { outs.write(_buffer, TOTAL_SIZE); } void TRecord770::read_from(istream& ins) { _buffer.fill(' ', TOTAL_SIZE); ins.read(_buffer.get_buffer(), TOTAL_SIZE); } const TField770& TRecord770::get_field(int pos) const { return tracciato().field(pos); } void TRecord770::set(const TField770& fld, const char* val) { TString256 str(val); // Ci sono campi di 100 caratteri! if (fld._type == AN) str.upper(); int lenstr = str.len(); if (lenstr > fld._len) { #ifdef DBG NFCHECK("Campo troppo lungo: '%s' (max. %d)", val, fld._len); #endif str.cut(lenstr = fld._len); } if (lenstr != fld._len) { str.trim(); if (fld._type == NU) str.right_just(fld._len, '0'); else str.left_just(fld._len); } _buffer.overwrite(str, fld._pos-1); } void TRecord770::set(int pos, const char* val) { const TField770& fld = tracciato().field(pos); set(fld, val); } void TRecord770::set(int pos, int val) { const TField770& fld = tracciato().field(pos); CHECKD(fld._type == NU, "Invalid numeric field ", pos); TString16 str; str.format("%d", val); set(fld, str); } void TRecord770::set(int pos, long val) { const TField770& fld = tracciato().field(pos); CHECKD(fld._type == NU, "Invalid numeric field ", pos); TString16 str; str.format("%ld", val); set(fld, str); } void TRecord770::set(int pos, const real& val) { const TField770& fld = tracciato().field(pos); CHECKD(fld._type == NU, "Invalid numeric field ", pos); const char* str = val.string(fld._len, 0); set(fld, str); } void TRecord770::set(int pos, const TDate& val) { const TField770& fld = tracciato().field(pos); CHECKD(fld._type == NU && (fld._len == 6 || fld._len == 8), "Invalid date field ", pos); const char* str; if (fld._len == 8) str = val.string(full, '\0', full, full, gma_date); else str = val.string(brief, '\0', full, full, gma_date); set(fld, str); } void TRecord770::set(int pos, char val) { const TField770& fld = get_field(pos); CHECKD(fld._type == AN && fld._len == 1, "Invalid char field ", pos); const char str[2] = { val, '\0' }; set(fld, str); } void TRecord770::set(int pos, bool val) { const TField770& fld = get_field(pos); CHECKD((fld._type == CB || fld._type == NU) && fld._len == 1, "Invalid boolean field ", pos); set(fld, val ? "1" : "0"); } const char* TRecord770::get(int pos, TString& str) const { const TField770& fld = get_field(pos); str = _buffer.mid(fld._pos-1, fld._len); return str.trim(); } int TRecord770::get_int(int pos) const { TString16 str; get(pos, str); return atoi(str); } char TRecord770::get_char(int pos) const { const TField770& fld = get_field(pos); CHECKD(fld._type == AN, "Invalid char field ", pos); return _buffer[fld._pos-1]; } // Calcola i blocchi necessari per contenere la stringa val int TRecord770::calculate_blocks(const char* val) const { // Il primo blocco contiene 16 caratteri, gli altri solo 15 perche' c'e' anche il + int blocks = 1; if (val && *val) { const int len = strlen(val); if (len > FIELD_SIZE) blocks += (len-FIELD_SIZE-1) / (FIELD_SIZE-1) + 1; } return blocks; } void TRecord770::tipo_record(char tipo) { _buffer[0] = tipo; tracciato().auto_fill(_buffer); } // Azzera tutti i campi non posizionali dei record di tipo E void TRecord770::azzera_campi_non_posizionali() { CHECK(ha_campi_non_posizionali(), "Impossibile azzerare un record senza campi non posizionali"); char* buf = _buffer.get_buffer() + HEADER_SIZE; memset(buf, ' ', USEABLE_SIZE); } // Aggiunge un campo non posizionale ai record di tipo E,F,G,H,J bool TRecord770::np_put(const char* code, const char* val) { CHECK(ha_campi_non_posizionali(), "Impossibile aggiungere campi non posizionali"); CHECKS(code && strlen(code) == CODE_SIZE, "Invalid field code ", code); //CHECKS(val && *val, "Can't add empty field ", code); if (!(val && *val)) return false; // Cerca il primo posto libero int pos; for (pos = HEADER_SIZE; pos < HEADER_SIZE+USEABLE_SIZE; pos += BLOCK_SIZE) { if (_buffer[pos] == ' ') break; } const int free_blocks = (USEABLE_SIZE - pos) / BLOCK_SIZE; const int needed_blocks = calculate_blocks(val); const bool ok = free_blocks >= needed_blocks; if (ok) // Se ci sono abbastanza blocchi liberi { TString80 str(val); str.upper(); const int lenstr = str.len(); for (int i = 0; i < lenstr; ) { _buffer.overwrite(code, pos); pos += CODE_SIZE; int maxlen = FIELD_SIZE; if (i > 0) { _buffer.overwrite("+", pos); pos++; maxlen--; } const TString& substr = str.mid(i, maxlen); _buffer.overwrite(substr, pos); pos += maxlen; i += maxlen; } } return ok; } bool TRecord770::np_put(const char* code, long val) { TString16 str; str.format("%16ld", val); return np_put(code, str); } bool TRecord770::np_put(const char* code, const real& val) { bool done = !val.is_zero(); if (done) { const TString& str = val.stringa(16, 2); done = np_put(code, str); } return done; } bool TRecord770::np_put(const char* code, char val) { bool done = val > ' '; if (done) { const char str[2] = { val, '\0' }; done = np_put(code, str); } return done; } bool TRecord770::np_put(const char* code, const TDate& date) { bool done = date.ok(); if (done) { TString16 str; str.format("%8s%02d%02d%04d", "", date.day(), date.month(), date.year()); done = np_put(code, str); } return done; } bool TRecord770::np_put(const char* code, bool cb) { bool done = false; if (cb) { TString16 str; str.format("%16d", 1); done = np_put(code, str); } return done; } bool TRecord770::np_get(int pos, TString& key, TString& val) const { CHECK(ha_campi_non_posizionali(), "Impossibile leggere campi non posizionali"); const int n = HEADER_SIZE + pos * BLOCK_SIZE; bool ok = false; if (n < HEADER_SIZE + USEABLE_SIZE) { ok = _buffer[n] > ' '; if (ok) { key = _buffer.mid(n, CODE_SIZE); val = _buffer.mid(n+CODE_SIZE, FIELD_SIZE); #ifdef DBG if (key == "AU001036") int cazzone = atoi(val); #endif } } return ok; } bool TRecord770::np_get_real(int pos, TString& key, real& val) const { TString16 str; const bool ok = np_get(pos, key, str); if (ok && str.full()) { str.replace(',', '.'); val = real(str); } else val = ZERO; return ok; } bool TRecord770::valid() const { const char tipo = tipo_record(); const bool ok = (tipo > ' ') && (strchr("ABEHJZ", tipo) != NULL); return ok; } TRecord770::TRecord770() : _buffer(TOTAL_SIZE, ' ') { } TRecord770::TRecord770(char tipo) : _buffer(TOTAL_SIZE, ' ') { tipo_record(tipo); } TRecord770::TRecord770(const TRecord770& rec) : _buffer(rec._buffer) { } TRecord770::~TRecord770() { }