2025-03-24 19:02:58 +03:00

524 lines
16 KiB
PHP

<?php
require_once('fixed/config/go_con.php');
ini_set('memory_limit', '2048M');
/*
$invoicesSumQuery = <<<SQL
SELECT SUM(invoices_details_has_how_pay.pay) AS sum
FROM invoices_details_has_how_pay
INNER JOIN invoices_details
ON invoices_details_has_how_pay.invoices_details_id = invoices_details.id
WHERE
invoices_details_has_how_pay.date_time >= '2023-01-01 00:00:00' AND
invoices_details_has_how_pay.date_time < '2023-04-01 00:00:00' AND
invoices_status_id = 1 AND
invoices_details_has_how_pay.how_pay_id IN (1,2,3,4,5,6,7,8,9,10)
SQL;
$result = mysqli_query($db, $invoicesSumQuery);
$sum = mysqli_fetch_assoc($result);
if (!$sum) {
die('sum could not be calculated');
}
$sum = $sum['sum'];
$bondsSumQuery = <<<SQL
SELECT SUM(bonds_details_has_how_pay.pay) AS sum
FROM bonds_details_has_how_pay
INNER JOIN bonds_details
ON bonds_details_has_how_pay.bonds_details_id = bonds_details.id
WHERE
bonds_details_has_how_pay.date_time >= '2023-01-01 00:00:00' AND
bonds_details_has_how_pay.date_time < '2023-04-01 00:00:00' AND
bonds_status_id = 1 AND
branch_id IN (2,3,4,5,6,7,8,10,11,12)
SQL;
$result = mysqli_query($db, $bondsSumQuery);
$sum = mysqli_fetch_assoc($result);
if (!$sum) {
die('sum could not be calculated');
}
$sum = $sum['sum'];
*/
echo "<pre>";
function inSubsetSum(array $a, float $t, array &$memo = []) : ?array {
$s = array_reduce($memo, function (?float $carry, array $value) {
return $carry + $value[1];
});
if ($s === $t) {
return $memo;
}
if ($s >= $t) {
return null;
}
$len = count($a);
$keys = array_keys($a);
for ($i = 0; $i < $len; ++$i) {
$k = $keys[$i];
$v = $a[$k];
$rem = array_slice($a, $i + 1, null, true);
$memo = array_merge($memo, [[$k, $v]]);
$res = inSubsetSum($rem, $t, $memo);
if ($res !== null) {
return $res;
}
}
return null;
}
function subsetSum(array $a, float $t) : ?array {
$subset = inSubsetSum($a, $t);
$result = [];
foreach ($subset as $_ => [$k, $v]) {
$result[$k] = $v;
}
return $result;
}
$invoiceQuery = <<<SQL
SELECT
invoices.id AS invoices_id,
book.id AS book_id,
invoices_details.id AS invoice_details_id,
invoices_details.branch_id AS branch_id,
invoices_details.pay AS pay,
book.tretment_id AS tretment_id,
invoices_details_has_how_pay.date_time AS date_time,
book_details.id AS book_details_id,
book_details.status_id AS book_details_status_id,
book_details.services_id AS services_id,
services.price AS price,
invoices_details_has_how_pay.how_pay_id AS how_pay_id
FROM invoices_details_has_how_pay
INNER JOIN invoices_details ON invoices_details.id = invoices_details_has_how_pay.invoices_details_id
INNER JOIN invoices ON invoices_details.invoices_id = invoices.id
INNER JOIN invoices_has_book ON invoices.id = invoices_has_book.invoices_id
INNER JOIN book ON book.id = invoices_has_book.book_id
INNER JOIN book_details ON book_details.book_id = book.id
INNER JOIN services ON services.id = book_details.services_id
JOIN (
SELECT `book_id`, MAX(`id`) AS `max_id`
FROM `book_details`
GROUP BY `book_id`
) `t1_max`
ON book_details.book_id = `t1_max`.`book_id` AND `book_details`.`id` = `t1_max`.`max_id`
WHERE
-- invoices_details_has_how_pay.date_time >= '2023-01-01 00:00:00' AND
-- invoices_details_has_how_pay.date_time < '2023-04-01 00:00:00' AND
invoices_status_id = 1 AND
invoices_details.branch_id IN (2,3,4,5,6,7,8,10,11,12) AND
invoices.id = 192501
ORDER BY invoices_details_has_how_pay.date_time DESC
SQL;
$result = mysqli_query($db, $invoiceQuery);
$error = mysqli_error($db);
if ($error) {
echo $error;
die;
}
$invoiceData = mysqli_fetch_all($result, MYSQLI_ASSOC);
$invoiceDiscountQuery = <<<SQL
SELECT
invoices_discount.discount AS total_discount,
invoices_discount_details.services_id AS service_id,
invoices_discount_details.reason AS reason,
invoices_discount_details.discount AS discount
FROM `invoices_discount_details`
INNER JOIN
invoices_discount
ON invoices_discount.id = invoices_discount_details.invoices_discount_id
INNER JOIN
invoices_details
ON invoices_details.id = invoices_discount.invoices_details_id
WHERE
(invoices_discount_details.services_id = ? OR invoices_discount_details.services_id = 0) AND
invoices_discount.invoices_details_id = ?
GROUP BY invoices_discount_details.reason
SQL;
$finalInvoiceData = [];
$year = '23';
$letter = 'I';
$branchData = [
'2' => ['1501', 0],
'3' => ['0701', 0],
'4' => ['2901', 0],
'5' => ['0602', 0],
'6' => ['KM01', 0],
'7' => ['VS01', 0],
'8' => ['VS02', 0],
'9' => ['PT07', 0],
'12' => ['2902', 0],
'13' => ['1502', 0],
];
$countQuery = <<<SQL
SELECT COUNT(*) AS count FROM invoices_has_book WHERE invoices_id = ?
SQL;
function getDecimalsLength(float $val) : int {
return strcspn(strrev((string) $val), '.');
}
function roundMoney(float $val, int $precision = 2) : string {
$decimals = getDecimalsLength($val);
for ($i = $decimals - 1; $i > ($precision - 1); --$i) {
$val = round($val, $i);
}
return number_format($val, 2);
}
$bundleQuery = <<<SQL
SELECT
services.id AS services_id,
services.price AS price,
bundle_services_has_services.how_many AS how_many
FROM bundle_services_has_services
INNER JOIN services ON services.id = bundle_services_has_services.services_id
WHERE
bundle_services_has_services.bundle_services_id = (
SELECT
bundle_services_id
FROM book_details_has_bundle_services
WHERE
book_details_id = (
SELECT MIN(id)
FROM book_details
WHERE
book_id = ? AND
status_id = 4
)
)
SQL;
function getTotalDiscount(int $invoiceId) : float {
global $db;
$stmt = mysqli_prepare($db, <<<SQL
SELECT invoices_discount.discount AS discount
FROM invoices_discount
INNER JOIN invoices_details ON invoices_details.id = invoices_discount.invoices_details_id
INNER JOIN invoices ON invoices.id = invoices_details.invoices_id
WHERE invoices.id = ?
SQL);
$stmt->bind_param('i', $invoiceId);
$stmt->execute();
$error = mysqli_error($db);
if ($error) {
echo $error;
die;
}
$result = $stmt->get_result();
$result = mysqli_fetch_all($result, MYSQLI_ASSOC);
if (count($result) == 0) {
return 0.0;
}
return $result[0]['discount'];
}
function processInvoice(array &$data, int $serviceCount) : array {
global $db;
global $invoiceDiscountQuery;
global $countQuery;
global $year;
global $letter;
global $finalInvoiceData;
global $branchData;
$detailsId = $data['invoice_details_id'];
$serviceId = $data['services_id'];
$data['discount'] = 0;
$stmt = mysqli_prepare($db, $invoiceDiscountQuery);
$stmt->bind_param('ii', $serviceId, $detailsId);
$stmt->execute();
$error = mysqli_error($db);
if ($error) {
echo $error;
die;
}
$result = $stmt->get_result();
$discountData = mysqli_fetch_all($result, MYSQLI_ASSOC);
$invoiceDiscounts = [];
foreach ($discountData as &$discount) {
// NOTE: this is for home visit services
if ($discount['service_id'] == 0) {
$countStmt = mysqli_prepare($db, $countQuery);
$countStmt->bind_param('i', $data['invoices_id']);
$countStmt->execute();
$error = mysqli_error($db);
if ($error) {
echo $error;
die;
}
$countResult = $countStmt->get_result();
$countResult = mysqli_fetch_all($countResult, MYSQLI_ASSOC);
$data['discount'] += $discount['total_discount'] / floatval($countResult[0]['count']);
$discount['discount'] = $discount['total_discount'] / floatval($countResult[0]['count']);
} else {
$data['discount'] += $discount['discount'];
}
$invoiceDiscounts[] = [
'reason' => $discount['reason'],
'discount' => $discount['discount'],
];
}
$totalAfterDiscount = $data['price'] * $serviceCount - $data['discount'];
$vat = $data['branch_id'] == 9 ? 0.0 : 15.0;
$totalAfterDiscountVat = $totalAfterDiscount * ($vat / 100);
$bData = &$branchData[$data['branch_id']];
$branchCode = $bData[0];
$bData[1] += 1;
$invoiceNumber = $bData[1];
$number = "{$year}{$letter}{$branchCode}";
$number .= str_pad("$invoiceNumber", 7, '0', STR_PAD_LEFT);
$total = $totalAfterDiscount + $totalAfterDiscountVat;
$total = round($total, 2);
if ($total <= $data['pay']) {
$data['price_no_vat'] = roundMoney($data['price']);
$data['total_discount'] = roundMoney($data['discount']);
$data['total_after_discount'] = roundMoney($totalAfterDiscount);
$data['vat'] = roundMoney($totalAfterDiscountVat);
$total = $totalAfterDiscount + $totalAfterDiscountVat;
$data['total'] = roundMoney($total);
} else {
echo ("WELCOME TO HELL");
var_dump([
'total' => $totalAfterDiscount + $totalAfterDiscountVat,
'pay' => $data['pay'],
]);
var_dump($data);
die;
}
return [
'branch_id' => $data['branch_id'],
'invoices_id' => $data['invoices_id'],
'book_id' => $data['book_id'],
'tretment_id' => $data['tretment_id'],
'number' => $number,
'date_time' => $data['date_time'],
'service_id' => $data['services_id'],
'price_no_vat' => $data['price_no_vat'],
'total_discount' => $data['total_discount'],
'total_after_discount' => $data['total_after_discount'],
'vat_rate' => $vat,
'vat' => $data['vat'],
'total' => $data['total'],
'quantity' => $serviceCount,
'how_pay_id' => $data['how_pay_id'],
'discount_details' => $invoiceDiscounts,
];
}
$invoicesTotals = [];
foreach ($invoiceData as &$data) {
// TODO: fix service bundles (where service_id == 0)
if ($data['services_id'] == 0) {
$stmt = mysqli_prepare($db, $bundleQuery);
$stmt->bind_param('i', $data['book_id']);
$stmt->execute();
$result = $stmt->get_result();
$bundleData = mysqli_fetch_all($result, MYSQLI_ASSOC);
foreach ($bundleData as $bundle) {
$c += 1;
$d = $data;
$serviceId = $bundle['services_id'];
$count = $bundle['how_many'];
$price = $bundle['price'];
$d['services_id'] = $serviceId;
$d['price'] = $price;
$dd = processInvoice($d, $count);
$id = $d['invoices_id'];
$invoicesTotals["{$id}"]['total'] += $dd['total_discount'];
$invoicesTotals["{$id}"]['service_count'] = $count;
$invoicesTotals["{$id}"]['indices'][] = count($finalInvoiceData);
$finalInvoiceData[] = $dd;
}
} else {
$id = $data['invoices_id'];
$dd = processInvoice($data, 1);
$invoicesTotals["{$id}"]['total'] += $dd['total_discount'];
$invoicesTotals["{$id}"]['service_count'] = 1;
$invoicesTotals["{$id}"]['indices'][] = count($finalInvoiceData);
$finalInvoiceData[] = $dd;
}
}
foreach ($invoicesTotals as $id => $d) {
$total = $d['total'];
$indices = $d['indices'];
$count = $d['service_count'];
$originalTotal = getTotalDiscount($id);
if ($originalTotal != $total) {
$diff = bcsub($originalTotal, $total, 2);
foreach ($indices as $index) {
$total = $finalInvoiceData[$index]['total'];
$mod = bcmod($total, 1, 2);
if ($mod == $diff) {
$discount = $finalInvoiceData[$index]['total_discount'];
$discount += $diff;
$price = $finalInvoiceData[$index]['price_no_vat'];
$totalAfterDiscount = $price * $count - $discount;
$totalAfterDiscountVat = $totalAfterDiscount * ($finalInvoiceData[$index]['vat_rate'] / 100);
$totalAfterDiscount = roundMoney($price - $discount);
$vat = roundMoney($totalAfterDiscountVat);
$total = roundMoney($totalAfterDiscount + $totalAfterDiscountVat);
$finalInvoiceData[$index]['total_discount'] = $discount;
$finalInvoiceData[$index]['total_after_discount'] = $totalAfterDiscount;
$finalInvoiceData[$index]['vat'] = $vat;
$finalInvoiceData[$index]['total'] = $total;
$discountDetails = $finalInvoiceData[$index]['discount_details'];
if ($discountDetails && count($discountDetails) > 0) {
$discountDetails[0]['discount'] = $discount;
$finalInvoiceData[$index]['discount_details'] = $discountDetails;
}
break;
} else {
echo "WTH";
die;
}
}
}
}
var_dump($finalInvoiceData);
die;
$sum = 0.0;
$desired = 4695115.53;
$subset = [];
$reached_desired = false;
foreach ($invoiceData as &$data) {
if ($sum == $desired) {
$reached_desired = true;
break;
} else if ($sum < $desired) {
$sum += $data['pay'];
$subset[$key] = $bond;
continue;
}
break;
}
$sahabiInvoicesTables = <<<SQL
CREATE TABLE IF NOT EXISTS `sahabi_invoices` (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
branch_id INT NOT NULL,
invoices_id INT NOT NULL,
book_id INT NOT NULL,
tretment_id INT NOT NULL,
number VARCHAR(14) NOT NULL,
date_time DATETIME NOT NULL,
service_id INT NOT NULL,
price_no_vat DECIMAL(10, 2) NOT NULL,
total_discount DECIMAL(10, 2) NOT NULL,
total_after_discount DECIMAL(10, 2) NOT NULL,
vat_rate DECIMAL(10, 2) DEFAULT NULL,
vat DECIMAL(10, 2) DEFAULT NULL,
total DECIMAL(10, 2) NOT NULL,
quantity INT NOT NULL,
how_pay_id INT NOT NULL
) ENGINE=INNODB;
CREATE TABLE IF NOT EXISTS `sahabi_invoices_discount_details` (
id INT NOT NULL PRIMARY KEY AUTO_INCREMENT,
reason VARCHAR(255) NOT NULL,
discount DECIMAL(10,2) NOT NULL,
sahabi_invoice_id INT NOT NULL,
FOREIGN KEY (sahabi_invoice_id)
REFERENCES sahabi_invoices(id)
ON DELETE RESTRICT ON UPDATE CASCADE
) ENGINE=INNODB;
SQL;
// $result = mysqli_query($db, $sahabiBonds);
echo mysqli_error($db);
foreach ($subset as $id => $bond) {
$bData = &$branchData[$bond['branch_id']];
$branchCode = $bData[0];
$bData[1] += 1;
$invoiceNumber = $bData[1];
$number = "{$year}{$letter}{$branchCode}";
$number .= str_pad("$invoiceNumber", 7, '0', STR_PAD_LEFT);
$noVat = $bond['pay'] / 1.15;
$vat = $bond['pay'] - $noVat;
$params = [
$bond['bonds_id'],
$bond['branch_id'],
$bond['tretment_id'],
$bond['bonds_type_type_id'],
$number,
$bond['date_time'],
$noVat,
$vat,
$bond['pay'],
$bond['how_pay_id'],
];
$insertQuery = <<<SQL
INSERT INTO `sahabi_bonds` (
bonds_id,
branch_id,
tretment_id,
bonds_type_type_id,
number,
date_time,
price_no_vat,
vat,
total,
how_pay_id
) VALUES (
?,
?,
?,
?,
?,
?,
?,
?,
?,
?
);
SQL;
$stmt = mysqli_prepare($db, $insertQuery);
$stmt->bind_param('ssiissdddi', ...$params);
// $stmt->execute();
}
// $desired = 655476.19;
// $subset = subsetSum($bonds, $desired);
// echo "done";
//
// $subsetSum = array_sum($subset);
// echo "<br>subset sum: $subsetSum";
echo "</pre>";