2026-06-01 10:02:36 +02:00
|
|
|
#include <QDebug>
|
2026-05-24 23:21:33 +02:00
|
|
|
#include "fiebdc.h"
|
|
|
|
|
//#include "globalvars.h" // Asumiendo que globalVars está definido aquí
|
|
|
|
|
|
|
|
|
|
#include <QDate>
|
|
|
|
|
|
|
|
|
|
FIEBDC::FIEBDC(QString filename, Budget* budget) {
|
|
|
|
|
__budget = budget;
|
|
|
|
|
__filename = filename;
|
|
|
|
|
if (__budget != nullptr) {
|
|
|
|
|
__budget->filename = __filename;
|
|
|
|
|
}
|
|
|
|
|
__cancel = false;
|
|
|
|
|
__format_list = {"FIEBDC-3/95", "FIEBDC-3/98", "FIEBDC-3/2002",
|
|
|
|
|
"FIEBDC-3/2004", "FIEBDC-3/2007"};
|
|
|
|
|
__character_sets_dict = {{"ANSI", "cp1252"},
|
|
|
|
|
{"850", "850"},
|
|
|
|
|
{"437", "cp437"}};
|
|
|
|
|
__file_format = "FIEBDC-3/2007";
|
|
|
|
|
//__generator = globalVars.name + " " + globalVars.version;
|
|
|
|
|
|
|
|
|
|
__character_set = "850";
|
|
|
|
|
initializePatterns();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FIEBDC::initializePatterns() {
|
|
|
|
|
__pattern = {
|
|
|
|
|
{"control_tilde", QRegularExpression(R"(((\r\n)| |\t)+~)")},
|
|
|
|
|
{"control_vbar", QRegularExpression(R"(((\r\n)| |\t)+\|)")},
|
|
|
|
|
{"control_backslash", QRegularExpression(R"(((\r\n)| |\t)+\\)")},
|
|
|
|
|
{"valid_code", QRegularExpression(R"([^A-Za-z0-9ñÑ.$#%&_])")},
|
|
|
|
|
{"special_char", QRegularExpression(R"([#%&])")},
|
|
|
|
|
{"no_float", QRegularExpression(R"([^\-0-9.])")},
|
|
|
|
|
{"formula", QRegularExpression(R"(.*[^0123456789\.()\+\-\*/\^abcdp ].*)")},
|
|
|
|
|
{"comment", QRegularExpression(R"(#.*\r\n)")},
|
|
|
|
|
{"empty_line", QRegularExpression(R"((\r\n) *\r\n)")},
|
|
|
|
|
{"space_before_backslash", QRegularExpression(R"(( )+\\)")},
|
|
|
|
|
{"space_after_backslash", QRegularExpression(R"(\\( )+)")},
|
|
|
|
|
{"start_noend_backslash", QRegularExpression(R"((\r\n\\\.*[^\\\])\r\n)")},
|
|
|
|
|
{"end_oper", QRegularExpression(R"((\+|-|\*|/|/^|@|&|<|>|<=|>=|=|!) *\r\n)")},
|
|
|
|
|
{"matricial_var", QRegularExpression(R"((\r\n *[%|\$][A-ZÑ].*=.*, ) *\r\n)")},
|
|
|
|
|
{"descomposition", QRegularExpression(R"(^([^:]+):(.*)$)")},
|
|
|
|
|
{"var", QRegularExpression(R"(^([$%][A-ZÑ][()0-9, ]*)=(.*)$)")},
|
|
|
|
|
{"after_first_tilde", QRegularExpression(R"(^[^~]*~)")},
|
|
|
|
|
{"end_control", QRegularExpression(R"(((\r\n)| |\t)+$)")}
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FIEBDC::cancel() {
|
|
|
|
|
__cancel = true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString FIEBDC::eraseControlCharacters(const QString& input) {
|
|
|
|
|
// Implementación de la función para eliminar caracteres de control
|
|
|
|
|
QString string = input;
|
|
|
|
|
string = string.replace(__pattern["control_tilde"], "~");
|
|
|
|
|
string = string.replace(__pattern["control_vbar"], "|");
|
|
|
|
|
// Uncomment if control_backslash processing is needed
|
|
|
|
|
// string = string.replace(__pattern["control_backslash"], "\\");
|
|
|
|
|
return string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool FIEBDC::validateCode(const QString& code) {
|
|
|
|
|
// Implementación de la función para validar el código
|
|
|
|
|
QRegularExpression re("^[A-Z0-9]+$");
|
|
|
|
|
return re.match(code).hasMatch();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QDate FIEBDC::parseDate(const QString& dateStr) {
|
|
|
|
|
/*parseDate(date)
|
|
|
|
|
|
|
|
|
|
date: in the format:
|
|
|
|
|
uneven len: add a Leading 0
|
|
|
|
|
len = 8 DDMMYYYY
|
|
|
|
|
len <= 6 DDMMYY “80/20”. >80 -> >1980 <80 -> <2080
|
|
|
|
|
len < 5 MMYY
|
|
|
|
|
len < 3 YY
|
|
|
|
|
Test date string and return a tuple (YYYY, MM, DD)
|
|
|
|
|
or None if the date format is invalid
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (dateStr.isEmpty()) {
|
|
|
|
|
return QDate();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString paddedDate = dateStr;
|
|
|
|
|
if (dateStr.length() % 2 != 0) {
|
|
|
|
|
paddedDate.prepend("0"); // Agregar un 0 inicial si la longitud es impar
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Intentar con diferentes formatos según la longitud
|
|
|
|
|
if (paddedDate.length() == 8) {
|
|
|
|
|
return QDate::fromString(paddedDate, "ddMMyyyy");
|
|
|
|
|
} else if (paddedDate.length() == 6) {
|
|
|
|
|
QString yearPrefix = paddedDate.right(2).toInt() < 80 ? "20" : "19";
|
|
|
|
|
return QDate::fromString(yearPrefix + paddedDate, "yyyyMMdd");
|
|
|
|
|
} else if (paddedDate.length() == 4) {
|
|
|
|
|
QString yearPrefix = paddedDate.right(2).toInt() < 80 ? "20" : "19";
|
|
|
|
|
return QDate::fromString(yearPrefix + paddedDate, "yyyyMM");
|
|
|
|
|
} else if (paddedDate.length() == 2) {
|
|
|
|
|
QString yearPrefix = paddedDate.toInt() < 80 ? "20" : "19";
|
|
|
|
|
return QDate::fromString(yearPrefix + paddedDate, "yyyy");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return QDate(); // Fecha inválida
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void FIEBDC::parseRecord(const QString& record) {
|
|
|
|
|
/*
|
|
|
|
|
parseRecord(record, interface)
|
|
|
|
|
|
|
|
|
|
record: the record line readed from the file whith the format:
|
|
|
|
|
type|field|field|subfield\\subfield|...
|
|
|
|
|
[a] nothing or "a"
|
|
|
|
|
{a} zero or more #-#twice#-# "a"
|
|
|
|
|
<a> one or more #-#twice#-# "a"
|
|
|
|
|
Types: V C D Y M N T K L Q J G E X B F A
|
|
|
|
|
V: Property and Version
|
|
|
|
|
1- [File_Owner]
|
|
|
|
|
2- Format_Version[\\DDMMYYYY]
|
|
|
|
|
3- [Program_Generator]
|
|
|
|
|
4- [Header]\\{Title\\}
|
|
|
|
|
5- [Chaters_set]
|
|
|
|
|
6- [Comment]
|
|
|
|
|
C: Record:
|
|
|
|
|
1- Code{\\Code}
|
|
|
|
|
2- [Unit]
|
|
|
|
|
3- [Summary]
|
|
|
|
|
4- {Price\\}
|
|
|
|
|
5- {Date\\}
|
|
|
|
|
6- [Type]
|
|
|
|
|
D or Y: DECOMPOSITION or ADD DECOMPOSITION
|
|
|
|
|
1- Parent Code
|
|
|
|
|
2- <Child Code\\ [Factor]\\ [Yield]>
|
|
|
|
|
M or N: MEASURE or ADD MEASURE
|
|
|
|
|
1- [Parent Code\\]Child Code
|
|
|
|
|
2- {Path\}
|
|
|
|
|
3- TOTAL MEASURE
|
|
|
|
|
4- {Type\\Comment\\Unit\\Length\\Width\\Height\\}
|
|
|
|
|
5- [Label]
|
|
|
|
|
T: Text
|
|
|
|
|
1- Code
|
|
|
|
|
2- Description text
|
|
|
|
|
K: Coefficients
|
|
|
|
|
1- { DN \\ DD \\ DS \\ DR \\ DI \\ DP \\ DC \\ DM \\ DIVISA \\ }
|
|
|
|
|
2- CI \\ GG \\ BI \\ BAJA \\ IVA
|
|
|
|
|
3- { DRC \\ DC \\ DRO \\ DFS \\ DRS \\ DFO \\ DUO \\ DI \\ DES \\ DN \\
|
|
|
|
|
DD \\ DS \\ DIVISA \\ }
|
|
|
|
|
4- [ n ]
|
|
|
|
|
L: Sheet of Conditions 1
|
|
|
|
|
A)
|
|
|
|
|
1- Empty
|
|
|
|
|
2- {Section Code\\Section Title}
|
|
|
|
|
B)
|
|
|
|
|
1- Record Code
|
|
|
|
|
2- {Section Code\\Section Text}
|
|
|
|
|
3- {Section Code\\RTF file}
|
|
|
|
|
4- {Section Code\\HTM file}
|
|
|
|
|
Q: Sheet of Conditions 2
|
|
|
|
|
1- Record Code
|
|
|
|
|
2- {Section Code\\Paragraph key\\{Field key;}\\}|
|
|
|
|
|
J: Sheet of Conditions 3
|
|
|
|
|
1- Paragraph code
|
|
|
|
|
2- [Paragraph text]
|
|
|
|
|
3- [RTF file]
|
|
|
|
|
4- [HTML file]
|
|
|
|
|
G: Grafic info
|
|
|
|
|
1- <grafic_file.ext\\>
|
|
|
|
|
E: Company
|
|
|
|
|
1- company Code
|
|
|
|
|
2 [ summary ]
|
|
|
|
|
3- [ name ]
|
|
|
|
|
4- { [ type ] \\ [ subname ] \\ [ address ] \\ [ postal_code ]
|
|
|
|
|
\\ [ town ] \\ [ province ] \\ [ country ] \\ { phone; }
|
|
|
|
|
\\ { fax; } \\ {contact_person; } \\ }
|
|
|
|
|
5- [ cif ] \\ [ web ] \\ [ email ] \\
|
|
|
|
|
X: Tecnical information
|
|
|
|
|
A)
|
|
|
|
|
1- Empty
|
|
|
|
|
2- < TI_Code \\ TI_Descitption \\ TI_Unit >
|
|
|
|
|
B)
|
|
|
|
|
1- Record_code
|
|
|
|
|
2- < TI_Code \\ TI_value >
|
|
|
|
|
F: #-#Adjunto#-# File
|
|
|
|
|
1- Record code
|
|
|
|
|
2- { Type \\ { Filenames; } \\ [Description] }
|
|
|
|
|
B: Change code
|
|
|
|
|
1- Record Code
|
|
|
|
|
2- New code
|
|
|
|
|
A: Labels
|
|
|
|
|
1- Record Code
|
|
|
|
|
2- <Label\\>
|
|
|
|
|
interface:
|
|
|
|
|
*/
|
|
|
|
|
QStringList fields = record.split("|");
|
|
|
|
|
if (fields.isEmpty()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString recordType = fields.at(0);
|
|
|
|
|
if (recordType == "V")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else if (recordType == "C")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else if (recordType == "D" || recordType == "Y")
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
else if (recordType == "T")
|
|
|
|
|
{
|
|
|
|
|
} else {
|
|
|
|
|
qDebug() << "Unknown record type:" << recordType << fields;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FIEBDC::parseV(QStringList fields)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
parseV(field_list)
|
|
|
|
|
|
|
|
|
|
field_list: field list of the record
|
|
|
|
|
0- V :Property and Version
|
|
|
|
|
1- [File_Owner]
|
|
|
|
|
2- Format_Version[\DDMMYYYY]
|
|
|
|
|
3- [Program_Generator]
|
|
|
|
|
4- [Header]\{Title\}
|
|
|
|
|
5- [Chaters_set]
|
|
|
|
|
6- [Comment]
|
|
|
|
|
7- [Data type]
|
|
|
|
|
8- [Number budget certificate]
|
|
|
|
|
9- [Date budget certificate]
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
if (fields.size() < 10) {
|
|
|
|
|
qWarning() << "Invalid 'V' record, insufficient fields:" << fields;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString owner = fields[1].trimmed();
|
|
|
|
|
QString versionDate = fields[2].trimmed();
|
|
|
|
|
QString generator = fields[3].trimmed();
|
|
|
|
|
QString headerTitle = fields[4].trimmed();
|
|
|
|
|
QString characterSet = fields[5].trimmed();
|
|
|
|
|
QString comment = fields[6].trimmed();
|
|
|
|
|
QString dataType = fields[7].trimmed();
|
|
|
|
|
QString numberCertificate = fields[8].trimmed();
|
|
|
|
|
QString dateCertificate = fields[9].trimmed();
|
|
|
|
|
|
|
|
|
|
// Process version and date
|
|
|
|
|
QStringList versionDateParts = versionDate.split("\\");
|
|
|
|
|
if (!versionDateParts.isEmpty()) {
|
|
|
|
|
auto fileFormat = versionDateParts[0];
|
|
|
|
|
qDebug() << "File format set to:" << fileFormat;
|
|
|
|
|
|
|
|
|
|
if (versionDateParts.size() > 1) {
|
|
|
|
|
QDate parsedDate = parseDate(versionDateParts[1]);
|
|
|
|
|
if (parsedDate.isValid()) {
|
|
|
|
|
qDebug() << "Parsed version date:" << parsedDate;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
# _____number of fields_____
|
|
|
|
|
# Any INFORMATION after last field separator is ignored
|
|
|
|
|
if len(field_list) > 10:
|
|
|
|
|
field_list = field_list[:10]
|
|
|
|
|
# If there are no sufficient fields, the fields are added
|
|
|
|
|
# with empty value:""
|
|
|
|
|
else:
|
|
|
|
|
field_list = field_list + [""]*(10-len(field_list))
|
|
|
|
|
# control character are erased: end of line, tab, space
|
|
|
|
|
# only leading and trailing whitespace in owner, generator, comment
|
|
|
|
|
# _____Fields_____
|
|
|
|
|
_record_type = self.delete_control_space(field_list[0])
|
|
|
|
|
_owner = field_list[1].strip()
|
|
|
|
|
_owner = self.delete_control(_owner)
|
|
|
|
|
_version_date = self.delete_control_space(field_list[2])
|
|
|
|
|
_generator = field_list[3].strip()
|
|
|
|
|
_generator = self.delete_control(_generator)
|
|
|
|
|
_header_title = field_list[4].strip()
|
|
|
|
|
_header_title = self.delete_control(_header_title)
|
|
|
|
|
_character_set = self.delete_control_space(field_list[5])
|
|
|
|
|
_comment = field_list[6].strip("\t \n\r")
|
|
|
|
|
_data_type = self.delete_control_space(field_list[7])
|
|
|
|
|
_number_certificate = self.delete_control_space(field_list[8])
|
|
|
|
|
__date_certificate = self.delete_control_space(field_list[9])
|
|
|
|
|
# _____Owner_____
|
|
|
|
|
self.__budget.setOwner(_owner)
|
|
|
|
|
# _____Version-Date_____
|
|
|
|
|
_version_date = _version_date.split("\\")
|
|
|
|
|
_file_format = _version_date[0]
|
|
|
|
|
if _file_format in self.__format_list:
|
|
|
|
|
self.__file_format = _file_format
|
|
|
|
|
_tuni = _("FIEBDC format: $1")
|
|
|
|
|
_uni = utils.mapping(_tuni, (_file_format,))
|
|
|
|
|
print(_uni)
|
|
|
|
|
|
|
|
|
|
if len(_version_date) > 1:
|
|
|
|
|
_date = _version_date[1]
|
|
|
|
|
if _date != "":
|
|
|
|
|
_parsed_date = self.parseDate(_date)
|
|
|
|
|
if _parsed_date is not None:
|
|
|
|
|
self.__budget.setDate(_parsed_date)
|
|
|
|
|
# _____Generator_____
|
|
|
|
|
# ignored field
|
|
|
|
|
_tuni = _("FIEBDC file generated by $1")
|
|
|
|
|
_uni = utils.mapping(_tuni, (_generator,))
|
|
|
|
|
print(_uni)
|
|
|
|
|
# _____Header_Title_____
|
|
|
|
|
_header_title = _header_title.split("\\")
|
|
|
|
|
_header_title = [_title.strip() for _title in _header_title]
|
|
|
|
|
_header = _header_title.pop(0)
|
|
|
|
|
_title = [ ]
|
|
|
|
|
for _title_index in _header_title:
|
|
|
|
|
if _title_index != "":
|
|
|
|
|
_title.append(_title_index)
|
|
|
|
|
if _header != "":
|
|
|
|
|
self.__budget.setTitleList([ _header, _title])
|
|
|
|
|
# _____Characters_set_____
|
|
|
|
|
# field parsed in readFile method
|
|
|
|
|
# _____Comment_____
|
|
|
|
|
if _comment != "":
|
|
|
|
|
self.__budget.setComment(_comment)
|
|
|
|
|
# _____Data type_____
|
|
|
|
|
# 1 -> Base data.
|
|
|
|
|
# 2 -> Budget.
|
|
|
|
|
# 3 -> Budget certificate.
|
|
|
|
|
# 4 -> Base date update.
|
|
|
|
|
try:
|
|
|
|
|
_data_type = int(_data_type)
|
|
|
|
|
except ValueError:
|
|
|
|
|
_data_type = ""
|
|
|
|
|
if _data_type == 3:
|
|
|
|
|
# _____Number budget certificate_____
|
|
|
|
|
try:
|
|
|
|
|
_number_certificate = int(_number_certificate)
|
|
|
|
|
except ValueError:
|
|
|
|
|
_number_certificate = ""
|
|
|
|
|
# _____Date budget certificate_____
|
|
|
|
|
if _date_certificate != "":
|
|
|
|
|
_parsed_date_certificate = self.parseDate(_date_certificate)
|
|
|
|
|
if _parsed_date_certificate is None:
|
|
|
|
|
_date_certificate = ""
|
|
|
|
|
else:
|
|
|
|
|
_date_certificate = _parsed_date_certificate
|
|
|
|
|
self.__budget.setBudgetype(_data_type)
|
|
|
|
|
self.__budget.setCertificateOrder(_number_certificate)
|
|
|
|
|
self.__budget.setCertificateDate(_parsed_date_cerfificate)
|
|
|
|
|
elif _data_type != "":
|
|
|
|
|
self.__budget.setBudgeType(_data_type)
|
|
|
|
|
self.__statistics.valid = self.__statistics.valid + 1
|
|
|
|
|
*/
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void FIEBDC::readFile(Budget* budget, QString filename) {
|
|
|
|
|
// Implementación de la función para leer el archivo
|
|
|
|
|
if (budget != nullptr) {
|
|
|
|
|
__budget = budget;
|
|
|
|
|
}
|
|
|
|
|
if (!filename.isEmpty()) {
|
|
|
|
|
__filename = filename;
|
|
|
|
|
}
|
|
|
|
|
// Lógica para leer el archivo
|
|
|
|
|
}
|