/*Requirements: nlohmann-json qrencode libharu cpr xlsxio C++20 */ #include "stdafx.h" #include "WB_QR.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include std::array separate(std::string s) { size_t pos = s.find(';'); std::string s1 = s.substr(0, pos); //Запись цифровой части кода в первый элемент массива std::string s2 = s.substr(pos + 1); //Запись части кода, которую нужно закодировать в QR во второй элемент массива return {s1, s2}; } static const HPDF_REAL ZOOM_SIZE = 6; //множитель размера пикселей QR-кодов static const HPDF_REAL INDENT = 0; //размер отступов от краёв страницы static const size_t QR_VERSION = 0; //от 0 до 40, если поставить версию меньше, чем требуется для количества ниформации, версия кода увеличится до минимальной подходящей // множитель 7 для пикселей QR-кода, ширина страницы 151 пиксель (~53 мм), отступы по бокам и сверх QR-кода 2 пикселя, отступ перед текстом 15 пикселей, текст высотой 19 и 29 пикселей, итого высота 176 int create_PDF(nlohmann::json data, std::string const& filename, std::string const& path) { HPDF_Doc pdf; pdf = HPDF_New(NULL, NULL); if (!pdf) { return 1; } //Проверка возможности создания объекта pdf для записи ответа HPDF_SetCompressionMode(pdf, HPDF_COMP_TEXT); HPDF_SetPageMode(pdf, HPDF_PAGE_MODE_USE_NONE); for (auto& i : data["data"]) { HPDF_Page page = HPDF_AddPage(pdf); //Создание новой страницы в pdf-документе std::array temp = separate(i); //Разделение кода на цифровую часть и часть, которую нужно перевести в QR-код size_t temp_size = temp[0].length(); QRcode* code = QRcode_encodeString(temp[1].c_str(), QR_VERSION, QR_ECLEVEL_L, QR_MODE_8, 1); //Кодирование QR-кода HPDF_REAL PAGE_WIDTH = (code->width) * ZOOM_SIZE + INDENT * 2; //Ширина страницы определяется по ширине QR-кода + отступы слева и справа HPDF_Page_SetWidth(page, PAGE_WIDTH); HPDF_REAL PAGE_HEIGHT = (int)((code->width) * ZOOM_SIZE * 1.171) + INDENT * 2 + 1; //Высота страницы включает в себя отступы, высоту QR-кода, и 17,1% высоты QR-кода под текст шрифта Courier с отступом от кода HPDF_Page_SetHeight(page, PAGE_HEIGHT); HPDF_Page_BeginText(page); HPDF_Page_MoveTextPos(page, 0, INDENT + 1); HPDF_Page_SetFontAndSize(page, HPDF_GetFont(pdf, "Courier-Bold", NULL), (int)((code->width) * ZOOM_SIZE * 0.13)); HPDF_Page_ShowText(page, temp[0].substr(0, temp_size - 4).c_str()); //Запись начала цифровой части под кодом HPDF_Page_SetFontAndSize(page, HPDF_GetFont(pdf, "Courier-Bold", NULL), (int)((code->width) * ZOOM_SIZE * 0.191)); HPDF_Page_ShowText(page, temp[0].substr(temp_size - 4).c_str()); //Запись последних четырёх цифр большим шрифтом HPDF_Page_EndText(page); HPDF_Page_SetCMYKFill(page, 1, 1, 1, 1); HPDF_Page_SetLineWidth(page, 0); for (int qy = 0; qy < (code->width); qy++) { for (int qx = 0; qx < (code->width); qx++) { unsigned char realqdata = code->data[qy * (code->width) + qx]; if (realqdata & 1) { HPDF_Page_Rectangle(page, ((qx * ZOOM_SIZE) + INDENT), (PAGE_HEIGHT - INDENT - ((qy + 1) * ZOOM_SIZE)), ZOOM_SIZE, ZOOM_SIZE); //Отметка чёрных модулей QR-кода на странице } } } QRcode_free(code); HPDF_Page_ClosePathEofillStroke(page); //Заливка намеченного QR-кода } std::filesystem::create_directories(path); HPDF_SaveToFile(pdf, (path + "/" + filename + ".pdf").c_str()); //Сохранение pdf-файла HPDF_Free(pdf); return 0; } void add_row(xlsxiowriter handle, std::array row) { xlsxiowrite_add_cell_string(handle, row[0].c_str()); xlsxiowrite_add_cell_string(handle, row[1].c_str()); xlsxiowrite_next_row(handle); return; } int create_XLSX(nlohmann::json data, std::string const& filename, std::string const& path) { xlsxiowriter handle; std::filesystem::create_directories(path); handle = xlsxiowrite_open((path + "/" + filename + ".xlsx").c_str(), "Sheet1"); int counter = 0; for (auto& i : data["data"]) { add_row(handle, separate(i)); } xlsxiowrite_close(handle); return 0; } int QR_generator(std::string SUPPLIER_ID, std::string LOGIN, std::string PASSWORD, int QTY, bool create_PDF_check, bool create_XLSX_check) { int pdf_result = 0; int xlsx_result = 0; std::chrono::time_point start_time = std::chrono::time_point_cast( std::chrono::current_zone()->to_local( std::chrono::system_clock::now())); //Сохранение момента времени старта запроса std::string filename = std::format("{:%d.%m.%Y_%H.%M.%S}", start_time); //Перевод текущих даты и времени в строку для названия файла cpr::Response r = cpr::Get(cpr::Url{ ("https://shk-reserv.wildberries.ru/srv/reservation/shk_reservation/api/shk/reserve_shk_safe_packages?supplier_id=" + SUPPLIER_ID + "&qty=" + std::to_string(QTY)) }, cpr::Authentication{ LOGIN, PASSWORD, cpr::AuthMode::BASIC }); //Отправка GET-запроса на сервер Wildberries nlohmann::json data = nlohmann::json::parse(r.text); PWSTR docpath; SHGetKnownFolderPath(FOLDERID_PublicDocuments, KF_FLAG_DEFAULT, NULL, &docpath); std::wstring strpath(docpath); CoTaskMemFree(docpath); std::string thstrpath(strpath.begin(), strpath.end()); thstrpath.append("/WB_QR/"); std::filesystem::create_directories(thstrpath + "JSON/" + std::format("{:%Y-%m}", start_time)); std::ofstream o(thstrpath + "JSON/" + std::format("{:%Y-%m}", start_time) + "/" + filename + ".json"); o << std::setw(4) << data << std::endl; //Запись ответа в отельный json-файл для резервного копирования if (data.find("errors") != data.end()) { return 2; } if (create_PDF_check) pdf_result = create_PDF(data, filename, thstrpath + "PDF/" + std::format("{:%Y-%m}", start_time)); //Создание pdf-файла if (create_XLSX_check) xlsx_result = create_XLSX(data, filename, thstrpath + "XLSX/" + std::format("{:%Y-%m}", start_time)); return (0 + pdf_result); } int JSON_to_PDF(std::string path) { std::ifstream f(path); nlohmann::json data = nlohmann::json::parse(f); if (data.find("errors") != data.end()) { return 2; } std::chrono::time_point start_time = std::chrono::time_point_cast( std::chrono::current_zone()->to_local( std::chrono::system_clock::now())); std::string filename = path.substr(path.find_last_of("/\\") + 1, path.find_last_of('.') - path.find_last_of("/\\") - 1); PWSTR docpath; SHGetKnownFolderPath(FOLDERID_PublicDocuments, KF_FLAG_DEFAULT, NULL, &docpath); std::wstring strpath(docpath); CoTaskMemFree(docpath); std::string thstrpath(strpath.begin(), strpath.end()); return create_PDF(data, filename, thstrpath + "/WB_QR/PDF/" + std::format("{:%Y-%m}", start_time)); } int JSON_to_XLSX(std::string path) { std::ifstream f(path); nlohmann::json data = nlohmann::json::parse(f); if (data.find("errors") != data.end()) { return 2; } std::chrono::time_point start_time = std::chrono::time_point_cast( std::chrono::current_zone()->to_local( std::chrono::system_clock::now())); std::string filename = path.substr(path.find_last_of("/\\") + 1, path.find_last_of('.') - path.find_last_of("/\\") - 1); PWSTR docpath; SHGetKnownFolderPath(FOLDERID_PublicDocuments, KF_FLAG_DEFAULT, NULL, &docpath); std::wstring strpath(docpath); CoTaskMemFree(docpath); std::string thstrpath(strpath.begin(), strpath.end()); return create_XLSX(data, filename, thstrpath + "/WB_QR/XLSX/" + std::format("{:%Y-%m}", start_time)); } std::string error_message(int result) { std::string message = ""; switch (result) { case 0: message = "Коды созданы успешно!"; break; case 1: message = "Ошибка создания pdf-файла"; break; case 2: message = "Ошибка запроса, проверьте правильность данных"; break; default: message = "Неизвестная ошибка"; } return message; }