WB-QR-full-MSVC-Qt-based / WB_QR_full_MSVC-Qt-based / WB_QR.cpp
WB_QR.cpp
Raw
/*Requirements:
nlohmann-json
qrencode
libharu
cpr
xlsxio
C++20
*/

#include "stdafx.h"
#include "WB_QR.h"
#include <qrencode.h>
#include <fstream>
#include <nlohmann/json.hpp>
#include <iostream>
#include <string>
#include <array>
#include <hpdf.h>
#include <cpr/cpr.h>
#include <chrono> 
#include <format>
#include <sstream>
#include <filesystem>
#include <xlsxio_write.h>
#include <ShlObj.h>


std::array<std::string, 2> 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<std::string, 2> 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<std::string, 2> 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<std::chrono::local_t, std::chrono::seconds> start_time = std::chrono::time_point_cast<std::chrono::seconds>(
		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<std::chrono::local_t, std::chrono::seconds> start_time = std::chrono::time_point_cast<std::chrono::seconds>(
		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<std::chrono::local_t, std::chrono::seconds> start_time = std::chrono::time_point_cast<std::chrono::seconds>(
		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;
}