This commit is contained in:
seb
2026-07-15 01:25:38 +02:00
parent 7fa839da4d
commit 056c9e18cd
21 changed files with 1181 additions and 64 deletions

View File

@@ -1,5 +1,6 @@
#pragma once
#include <algorithm>
#include <cctype>
#include <cmath>
#include <ctime>
#include <chrono>
@@ -297,6 +298,26 @@ inline bool is_walk_in_order(const nlohmann::json& order) {
&& billing.value("firstName", "").empty();
}
inline std::string resolve_auftrag_c_kunden_nr(const nlohmann::json& order) {
if (is_walk_in_order(order)) return "0";
return order.value("customerNumber", "");
}
// POS settings.invoiceSetting: 0 = external/POS invoice (nIstExterneRechnung=1).
inline int resolve_n_ist_externe_rechnung(const nlohmann::json& order) {
if (!order.contains("settings") || order["settings"].is_null()) return 1;
const auto& settings = order["settings"];
if (!settings.contains("invoiceSetting")) return 1;
const auto& inv = settings["invoiceSetting"];
if (inv.is_boolean()) return inv.get<bool>() ? 0 : 1;
if (inv.is_number_integer()) return inv.get<int>() == 1 ? 0 : 1;
if (inv.is_string()) {
std::string s = inv.get<std::string>();
return (s == "1" || s == "true") ? 0 : 1;
}
return 1;
}
inline std::pair<int,int> create_customer(OdbcPool::Connection* c, const std::string& customer_number,
const nlohmann::json& address, const Defaults& defaults) {
const nlohmann::json a = address.is_null() ? nlohmann::json::object() : address;
@@ -484,14 +505,27 @@ inline int parse_pos_auftrag_id(const std::string& external_id) {
try { return std::stoi(external_id); } catch (...) { return 0; }
}
inline bool external_order_numbers_match(const std::string& mapped, const std::string& incoming) {
if (incoming.empty()) return true;
if (mapped.size() != incoming.size()) return false;
for (size_t i = 0; i < mapped.size(); ++i) {
if (std::tolower(static_cast<unsigned char>(mapped[i]))
!= std::tolower(static_cast<unsigned char>(incoming[i]))) {
return false;
}
}
return true;
}
// PosOrderCreationService.CheckIfOrderExists — already-imported POS order.
inline std::optional<std::pair<int, std::string>> find_existing_pos_order(
OdbcPool::Connection* c, int kPosAuftrag) {
OdbcPool::Connection* c, int kPosAuftrag, const std::string& external_order_number) {
int kShopSubShop = get_active_shop_subshop_id();
if (kPosAuftrag <= 0 || kShopSubShop <= 0) return std::nullopt;
const char* sql =
"SELECT TOP 1 m.kAuftrag, a.cAuftragsNr FROM Pos.tAuftragMapping m "
"SELECT TOP 1 m.kAuftrag, a.cAuftragsNr, ISNULL(a.cExterneAuftragsnummer, '') AS cExterneAuftragsnummer "
"FROM Pos.tAuftragMapping m "
"LEFT JOIN Verkauf.tAuftrag a ON a.kAuftrag = m.kAuftrag "
"WHERE m.kPosAuftrag = ? AND m.kShopSubShop = ? AND m.kAuftrag IS NOT NULL "
"ORDER BY m.kAuftrag DESC";
@@ -509,6 +543,10 @@ inline std::optional<std::pair<int, std::string>> find_existing_pos_order(
int kAuftrag = std::stoi(rs[0][0].str);
if (kAuftrag <= 0) return std::nullopt;
std::string order_number = rs[0].size() > 1 ? rs[0][1].str : "";
std::string mapped_external = rs[0].size() > 2 ? rs[0][2].str : "";
if (!external_order_numbers_match(mapped_external, external_order_number)) {
return std::nullopt;
}
return std::make_pair(kAuftrag, order_number);
}
@@ -516,22 +554,23 @@ inline void upsert_pos_order_mapping(OdbcPool::Connection* c, int kAuftrag, int
int kShopSubShop = get_active_shop_subshop_id();
if (kPosAuftrag <= 0 || kShopSubShop <= 0) return;
const char* sql =
"MERGE INTO Pos.tAuftragMapping WITH (HOLDLOCK) AS Target "
"USING (SELECT ? AS kAuftrag, ? AS kPosAuftrag, ? AS kShopSubShop) AS Source "
"ON Target.kPosAuftrag = Source.kPosAuftrag AND Target.kShopSubShop = Source.kShopSubShop "
"WHEN MATCHED THEN UPDATE SET Target.kAuftrag = Source.kAuftrag "
"WHEN NOT MATCHED BY TARGET THEN "
"INSERT (kAuftrag, kPosAuftrag, kShopSubShop) "
"VALUES (Source.kAuftrag, Source.kPosAuftrag, Source.kShopSubShop)";
ResultSet rs;
std::vector<Param> del_ps = {
{ParamType::Int, "", kPosAuftrag},
{ParamType::Int, "", kShopSubShop},
};
get_pool().execute(c,
"DELETE FROM Pos.tAuftragMapping WHERE kPosAuftrag = ? AND kShopSubShop = ?",
del_ps, rs);
std::vector<Param> ps = {
std::vector<Param> ins_ps = {
{ParamType::Int, "", kAuftrag},
{ParamType::Int, "", kPosAuftrag},
{ParamType::Int, "", kShopSubShop}
{ParamType::Int, "", kShopSubShop},
};
ResultSet rs;
get_pool().execute(c, sql, ps, rs);
get_pool().execute(c,
"INSERT INTO Pos.tAuftragMapping (kAuftrag, kPosAuftrag, kShopSubShop) VALUES (?, ?, ?)",
ins_ps, rs);
}
inline void insert_pos_order_position_mapping(OdbcPool::Connection* c, int kAuftragPosition,
@@ -606,11 +645,13 @@ inline nlohmann::json create_order(const nlohmann::json& order) {
auto* c = guard.get();
int kPosAuftrag = parse_pos_auftrag_id(order.value("externalId", ""));
std::string external_order_number = order.value("externalOrderNumber", "");
if (kPosAuftrag > 0) {
if (auto existing = find_existing_pos_order(c, kPosAuftrag)) {
if (auto existing = find_existing_pos_order(c, kPosAuftrag, external_order_number)) {
return {
{"orderId", std::to_string(existing->first)},
{"orderNumber", existing->second}
{"orderNumber", existing->second},
{"alreadyExists", true}
};
}
}
@@ -645,12 +686,12 @@ inline nlohmann::json create_order(const nlohmann::json& order) {
" (cAuftragsNr, dErstellt, nKomplettAusgeliefert, kBenutzer, kKunde, kBenutzerErstellt, nType, fFaktor,"
" kFirmaHistory, kSprache, cVersandlandWaehrung, fVersandlandWaehrungFaktor, fFinanzierungskosten,"
" cWaehrung, kPlattform, kShop, cKundenNr, cVersandlandISO, kVersandArt, kZahlungsart, kKundengruppe,"
" cExterneAuftragsnummer)"
" cExterneAuftragsnummer, nIstExterneRechnung, cInet, nIstReadOnly, kShopauftrag, nLieferPrioritaet)"
" OUTPUT inserted.kAuftrag INTO @t"
" VALUES (?, ?, 0, ?, ?, ?, 1, 1.0,"
" ?, ?, ?, 1.0, 0.0,"
" ?, ?, ?, ?, ?, ?, ?, ?,"
" ?);"
" ?, ?, ?, ?, 0, 10);"
"SELECT kAuftrag FROM @t";
std::string shipping_iso = order.value("shippingAddress", nlohmann::json::object()).value("countryIso", "DE");
@@ -658,6 +699,8 @@ inline nlohmann::json create_order(const nlohmann::json& order) {
[](unsigned char ch) { return std::toupper(ch); });
std::string currency_iso = order.value("currencyIso", "EUR");
std::string cKundenNr = resolve_auftrag_c_kunden_nr(order);
int nIstExterneRechnung = resolve_n_ist_externe_rechnung(order);
std::vector<Param> ps = {
{ParamType::NVarChar, cAuftragsNr, 0},
{ParamType::NVarChar, order_date_sql(order_date_tm), 0},
@@ -670,12 +713,15 @@ inline nlohmann::json create_order(const nlohmann::json& order) {
{ParamType::NVarChar, currency_iso, 0},
{ParamType::Int, "", defaults.kPlattform},
{ParamType::Int, "", active_shop == 0 ? -1 : active_shop},
{ParamType::NVarChar, order.value("customerNumber", ""), 0},
{ParamType::NVarChar, cKundenNr, 0},
{ParamType::NVarChar, shipping_iso, 0},
{ParamType::Int, "", defaults.kVersandArt},
{ParamType::Int, "", json_int(zahlungsart, "kZahlungsart", 0)},
{ParamType::Int, "", kKundengruppe},
{ParamType::NVarChar, order.value("externalOrderNumber", ""), 0}
{ParamType::NVarChar, order.value("externalOrderNumber", ""), 0},
{ParamType::Int, "", nIstExterneRechnung},
{ParamType::NVarChar, "Y", 0},
{ParamType::Int, "", 2},
};
if (active_shop == 0) {
ps[11] = Param::null_int();
@@ -719,7 +765,11 @@ inline nlohmann::json create_order(const nlohmann::json& order) {
if (!get_pool().commit(c)) throw std::runtime_error("failed to commit transaction");
return { {"orderId", std::to_string(kAuftrag)}, {"orderNumber", cAuftragsNr} };
return {
{"orderId", std::to_string(kAuftrag)},
{"orderNumber", cAuftragsNr},
{"alreadyExists", false}
};
} catch (const std::exception&) {
try { get_pool().rollback(c); } catch (...) {}
throw;