feat: new statistics per payment method (#124)
* feat: new statistics per payment method * fix: fix typo on english language file * fix: use translation text for deleting subscriptions
This commit is contained in:
parent
fc2ca267e0
commit
6200fa5e87
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "Aufgeteilte Ansichten",
|
'split_views' => "Aufgeteilte Ansichten",
|
||||||
'category_split' => "Kategorien",
|
'category_split' => "Kategorien",
|
||||||
'household_split' => "Haushalt",
|
'household_split' => "Haushalt",
|
||||||
|
'payment_method_split' => "Zahlungsmethode",
|
||||||
// About page
|
// About page
|
||||||
'about_and_credits' => "Informationen und Danksagungen",
|
'about_and_credits' => "Informationen und Danksagungen",
|
||||||
'license' => "Lizenz",
|
'license' => "Lizenz",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "Διαχωρισμένες προβολές",
|
'split_views' => "Διαχωρισμένες προβολές",
|
||||||
'category_split' => "Διαχωρισμός κατηγορίας",
|
'category_split' => "Διαχωρισμός κατηγορίας",
|
||||||
'household_split' => "Διαχωρισμός νοικοκυριού",
|
'household_split' => "Διαχωρισμός νοικοκυριού",
|
||||||
|
'payment_method_split' => "Διαχωρισμός τρόπου πληρωμής",
|
||||||
// About page
|
// About page
|
||||||
'about_and_credits' => "Σχετικά και Credits",
|
'about_and_credits' => "Σχετικά και Credits",
|
||||||
'license' => "License",
|
'license' => "License",
|
||||||
|
|||||||
@ -44,7 +44,7 @@ $i18n = [
|
|||||||
"weeks" => "weeks",
|
"weeks" => "weeks",
|
||||||
"months" => "months",
|
"months" => "months",
|
||||||
"years" => "years",
|
"years" => "years",
|
||||||
"external_url" => "Visit Externarl URL",
|
"external_url" => "Visit External URL",
|
||||||
"empty_page" => "Empty Page",
|
"empty_page" => "Empty Page",
|
||||||
// Subscription form
|
// Subscription form
|
||||||
"add_subscription" => "Add subscription",
|
"add_subscription" => "Add subscription",
|
||||||
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "Split Views",
|
'split_views' => "Split Views",
|
||||||
'category_split' => "Category Split",
|
'category_split' => "Category Split",
|
||||||
'household_split' => "Household Split",
|
'household_split' => "Household Split",
|
||||||
|
'payment_method_split' => "Payment Method Split",
|
||||||
// About page
|
// About page
|
||||||
'about_and_credits' => "About and Credits",
|
'about_and_credits' => "About and Credits",
|
||||||
'license' => "License",
|
'license' => "License",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "Vistas Divididas",
|
'split_views' => "Vistas Divididas",
|
||||||
'category_split' => "División por Categoría",
|
'category_split' => "División por Categoría",
|
||||||
'household_split' => "División por Hogar",
|
'household_split' => "División por Hogar",
|
||||||
|
'payment_method_split' => "División por Método de Pago",
|
||||||
// About page
|
// About page
|
||||||
'about_and_credits' => "Acerca de y Créditos",
|
'about_and_credits' => "Acerca de y Créditos",
|
||||||
'license' => "Licencia",
|
'license' => "Licencia",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "Vues partagées",
|
'split_views' => "Vues partagées",
|
||||||
'category_split' => "Répartition par catégorie",
|
'category_split' => "Répartition par catégorie",
|
||||||
'household_split' => "Répartition du ménage",
|
'household_split' => "Répartition du ménage",
|
||||||
|
'payment_method_split' => "Répartition par méthode de paiement",
|
||||||
// Page À propos
|
// Page À propos
|
||||||
'about_and_credits' => "À propos et crédits",
|
'about_and_credits' => "À propos et crédits",
|
||||||
'license' => "Licence",
|
'license' => "Licence",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "分割表示",
|
'split_views' => "分割表示",
|
||||||
'category_split' => "カテゴリ別",
|
'category_split' => "カテゴリ別",
|
||||||
'household_split' => "世帯別",
|
'household_split' => "世帯別",
|
||||||
|
'payment_method_split' => "支払い方法別",
|
||||||
// About page
|
// About page
|
||||||
'about_and_credits' => "概要とクレジット",
|
'about_and_credits' => "概要とクレジット",
|
||||||
'license' => "License",
|
'license' => "License",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "Vistas Divididas",
|
'split_views' => "Vistas Divididas",
|
||||||
'category_split' => "Por Categoria",
|
'category_split' => "Por Categoria",
|
||||||
'household_split' => "Por Membro",
|
'household_split' => "Por Membro",
|
||||||
|
'payment_method_split' => "Por Método de Pagamento",
|
||||||
// About page
|
// About page
|
||||||
'about_and_credits' => "Sobre e Créditos",
|
'about_and_credits' => "Sobre e Créditos",
|
||||||
'license' => "Licença",
|
'license' => "Licença",
|
||||||
|
|||||||
@ -78,6 +78,7 @@ $i18n = [
|
|||||||
'split_views' => "Bölünmüş Görünümler",
|
'split_views' => "Bölünmüş Görünümler",
|
||||||
'category_split' => "Kategori Bölümü",
|
'category_split' => "Kategori Bölümü",
|
||||||
'household_split' => "Hane Bölümü",
|
'household_split' => "Hane Bölümü",
|
||||||
|
'payment_method_split' => "Ödeme Yöntemi Bölümü",
|
||||||
// About page
|
// About page
|
||||||
'about_and_credits' => "Hakkında ve Teşekkürler",
|
'about_and_credits' => "Hakkında ve Teşekkürler",
|
||||||
'license' => "Lisans",
|
'license' => "Lisans",
|
||||||
|
|||||||
@ -83,6 +83,7 @@ $i18n = [
|
|||||||
'split_views' => "拆分视图",
|
'split_views' => "拆分视图",
|
||||||
'category_split' => "分类视图",
|
'category_split' => "分类视图",
|
||||||
'household_split' => "家庭视图",
|
'household_split' => "家庭视图",
|
||||||
|
'payment_method_split' => "支付方式视图",
|
||||||
|
|
||||||
// 关于页面
|
// 关于页面
|
||||||
'about_and_credits' => "关于和鸣谢",
|
'about_and_credits' => "关于和鸣谢",
|
||||||
|
|||||||
@ -83,6 +83,7 @@ $i18n = [
|
|||||||
'split_views' => "分割表示",
|
'split_views' => "分割表示",
|
||||||
'category_split' => "類別表示",
|
'category_split' => "類別表示",
|
||||||
'household_split' => "家庭表示",
|
'household_split' => "家庭表示",
|
||||||
|
'payment_method_split' => "付款方式表示",
|
||||||
|
|
||||||
// 關於頁面
|
// 關於頁面
|
||||||
'about_and_credits' => "關於和致謝",
|
'about_and_credits' => "關於和致謝",
|
||||||
|
|||||||
@ -145,7 +145,7 @@ function handleFileSelect(event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function deleteSubscription(id) {
|
function deleteSubscription(id) {
|
||||||
if (confirm("Are you sure you want to delete this subscription?")) {
|
if (confirm(translate('confirm_delete_subscription'))) {
|
||||||
fetch(`endpoints/subscription/delete.php?id=${id}`, {
|
fetch(`endpoints/subscription/delete.php?id=${id}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
})
|
})
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
failed_to_load_subscription: "Fehler beim Laden des Abonnements",
|
failed_to_load_subscription: "Fehler beim Laden des Abonnements",
|
||||||
edit_subscription: "Abonnement bearbeiten",
|
edit_subscription: "Abonnement bearbeiten",
|
||||||
add_subscription: "Abonnement hinzufügen",
|
add_subscription: "Abonnement hinzufügen",
|
||||||
|
confirm_delete_subscription: "Sind Sie sicher, dass Sie dieses Abonnement löschen möchten?",
|
||||||
// Settings
|
// Settings
|
||||||
network_response_error: "Netzwerkfehler",
|
network_response_error: "Netzwerkfehler",
|
||||||
failed_add_member: "Hinzufügen von Mitglied fehlgeschlagen",
|
failed_add_member: "Hinzufügen von Mitglied fehlgeschlagen",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
failed_to_load_subscription: "Απέτυχε η φόρτωση της συνδρομής",
|
failed_to_load_subscription: "Απέτυχε η φόρτωση της συνδρομής",
|
||||||
edit_subscription: "Επεξεργασία συνδρομής",
|
edit_subscription: "Επεξεργασία συνδρομής",
|
||||||
add_subscription: "Προσθήκη συνδρομής",
|
add_subscription: "Προσθήκη συνδρομής",
|
||||||
|
confirm_delete_subscription: "Είστε σίγουρος ότι θέλετε να διαγράψετε αυτή τη συνδρομή;",
|
||||||
// Settings
|
// Settings
|
||||||
network_response_error: "Η ανταπόκριση του δικτύου δεν ήταν εντάξει",
|
network_response_error: "Η ανταπόκριση του δικτύου δεν ήταν εντάξει",
|
||||||
failed_add_member: "Αποτυχία προσθήκης μέλους",
|
failed_add_member: "Αποτυχία προσθήκης μέλους",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
failed_to_load_subscription: "Failed to load subscription",
|
failed_to_load_subscription: "Failed to load subscription",
|
||||||
edit_subscription: "Edit subscription",
|
edit_subscription: "Edit subscription",
|
||||||
add_subscription: "Add subscription",
|
add_subscription: "Add subscription",
|
||||||
|
confirm_delete_subscription: "Are you sure you want to delete this subscription?",
|
||||||
// Settings
|
// Settings
|
||||||
network_response_error: "Network response was not ok",
|
network_response_error: "Network response was not ok",
|
||||||
failed_add_member: "Failed to add member",
|
failed_add_member: "Failed to add member",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
failed_to_load_subscription: "Error al cargar la suscripción",
|
failed_to_load_subscription: "Error al cargar la suscripción",
|
||||||
edit_subscription: "Editar suscripción",
|
edit_subscription: "Editar suscripción",
|
||||||
add_subscription: "Añadir suscripción",
|
add_subscription: "Añadir suscripción",
|
||||||
|
confirm_delete_subscription: "¿Estás seguro de que quieres eliminar esta suscripción?",
|
||||||
// Settings
|
// Settings
|
||||||
network_response_error: "Error en la respuesta de la red",
|
network_response_error: "Error en la respuesta de la red",
|
||||||
failed_add_member: "Error al añadir miembro",
|
failed_add_member: "Error al añadir miembro",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
failed_to_load_subscription: "Impossible de charger l'abonnement",
|
failed_to_load_subscription: "Impossible de charger l'abonnement",
|
||||||
edit_subscription: "Modifier l'abonnement",
|
edit_subscription: "Modifier l'abonnement",
|
||||||
add_subscription: "Ajouter un abonnement",
|
add_subscription: "Ajouter un abonnement",
|
||||||
|
confirm_delete_subscription: "Êtes-vous sûr de vouloir supprimer cet abonnement ?",
|
||||||
// Paramètres
|
// Paramètres
|
||||||
network_response_error: "La réponse du réseau n'était pas correcte",
|
network_response_error: "La réponse du réseau n'était pas correcte",
|
||||||
failed_add_member: "Échec de l'ajout du membre",
|
failed_add_member: "Échec de l'ajout du membre",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
failed_to_load_subscription: "定期購入の読み込みに失敗しました",
|
failed_to_load_subscription: "定期購入の読み込みに失敗しました",
|
||||||
edit_subscription: "定期購入の編集",
|
edit_subscription: "定期購入の編集",
|
||||||
add_subscription: "定期購入の追加",
|
add_subscription: "定期購入の追加",
|
||||||
|
confirm_delete_subscription: "この定期購入を削除してもよろしいですか?",
|
||||||
// Settings
|
// Settings
|
||||||
network_response_error: "ネットワークの応答異常",
|
network_response_error: "ネットワークの応答異常",
|
||||||
failed_add_member: "世帯員の追加に失敗",
|
failed_add_member: "世帯員の追加に失敗",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
'failed_to_load_subscription': 'Falha ao carregar a subscrição',
|
'failed_to_load_subscription': 'Falha ao carregar a subscrição',
|
||||||
'edit_subscription': 'Editar subscrição',
|
'edit_subscription': 'Editar subscrição',
|
||||||
'add_subscription': 'Adicionar subscrição',
|
'add_subscription': 'Adicionar subscrição',
|
||||||
|
'confirm_delete_subscription': 'Tem a certeza de que deseja eliminar esta subscrição?',
|
||||||
// Settings
|
// Settings
|
||||||
'network_response_error': 'Erro de resposta de rede',
|
'network_response_error': 'Erro de resposta de rede',
|
||||||
'failed_add_member': 'Falha ao adicionar membro',
|
'failed_add_member': 'Falha ao adicionar membro',
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
failed_to_load_subscription: "Abonelik yüklenemedi",
|
failed_to_load_subscription: "Abonelik yüklenemedi",
|
||||||
edit_subscription: "Aboneliği Düzenle",
|
edit_subscription: "Aboneliği Düzenle",
|
||||||
add_subscription: "Abonelik Ekle",
|
add_subscription: "Abonelik Ekle",
|
||||||
|
confirm_delete_subscription: "Bu aboneliği silmek istediğinizden emin misiniz?",
|
||||||
// Ayarlar
|
// Ayarlar
|
||||||
network_response_error: "Ağ yanıtı kabul edilmedi",
|
network_response_error: "Ağ yanıtı kabul edilmedi",
|
||||||
failed_add_member: "Üye eklenemedi",
|
failed_add_member: "Üye eklenemedi",
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
'failed_to_load_subscription': "加载订阅失败",
|
'failed_to_load_subscription': "加载订阅失败",
|
||||||
'edit_subscription': "编辑订阅",
|
'edit_subscription': "编辑订阅",
|
||||||
'add_subscription': "添加订阅",
|
'add_subscription': "添加订阅",
|
||||||
|
'confirm_delete_subscription': "您确定要删除此订阅吗?",
|
||||||
// Settings
|
// Settings
|
||||||
'network_response_error': "网络响应不正常",
|
'network_response_error': "网络响应不正常",
|
||||||
'failed_add_member': '添加成员失败',
|
'failed_add_member': '添加成员失败',
|
||||||
|
|||||||
@ -7,6 +7,7 @@ let i18n = {
|
|||||||
'failed_to_load_subscription': "讀取訂閱失敗",
|
'failed_to_load_subscription': "讀取訂閱失敗",
|
||||||
'edit_subscription': "編輯訂閱",
|
'edit_subscription': "編輯訂閱",
|
||||||
'add_subscription': "新增訂閱",
|
'add_subscription': "新增訂閱",
|
||||||
|
'confirm_delete_subscription': "您確定要刪除此訂閱嗎?",
|
||||||
// Settings
|
// Settings
|
||||||
'network_response_error': "網路無回應",
|
'network_response_error': "網路無回應",
|
||||||
'failed_add_member': '新增成員失敗',
|
'failed_add_member': '新增成員失敗',
|
||||||
|
|||||||
@ -8,7 +8,13 @@ function loadGraph(container, dataPoints, currency, run) {
|
|||||||
datasets: [{
|
datasets: [{
|
||||||
data: dataPoints.map(point => point.y),
|
data: dataPoints.map(point => point.y),
|
||||||
}],
|
}],
|
||||||
labels: dataPoints.map(point => `${point.label} (${new Intl.NumberFormat(navigator.language, { style: 'currency', currency }).format(point.y)})`),
|
labels: dataPoints.map(point => {
|
||||||
|
if (currency) {
|
||||||
|
return `${point.label} (${new Intl.NumberFormat(navigator.language, { style: 'currency', currency }).format(point.y)})`;
|
||||||
|
} else {
|
||||||
|
return `${point.label} (${new Intl.NumberFormat(navigator.language).format(point.y)})`;
|
||||||
|
}
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
animation: {
|
animation: {
|
||||||
|
|||||||
39
stats.php
39
stats.php
@ -60,6 +60,17 @@ while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
|||||||
$categoryCost[$categoryId]['name'] = $row['name'];
|
$categoryCost[$categoryId]['name'] = $row['name'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get payment methods
|
||||||
|
$categories = array();
|
||||||
|
$query = "SELECT * FROM payment_methods WHERE enabled = 1";
|
||||||
|
$result = $db->query($query);
|
||||||
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||||
|
$paymentMethodId = $row['id'];
|
||||||
|
$paymentMethodCount[$paymentMethodId] = $row;
|
||||||
|
$paymentMethodCount[$paymentMethodId]['count'] = 0;
|
||||||
|
$paymentMethodCount[$paymentMethodId]['name'] = $row['name'];
|
||||||
|
}
|
||||||
|
|
||||||
// Get code of main currency to display on statistics
|
// Get code of main currency to display on statistics
|
||||||
$query = "SELECT c.code
|
$query = "SELECT c.code
|
||||||
FROM currencies c
|
FROM currencies c
|
||||||
@ -84,7 +95,7 @@ $mostExpensiveSubscription = 0;
|
|||||||
$amountDueThisMonth = 0;
|
$amountDueThisMonth = 0;
|
||||||
$totalCostPerMonth = 0;
|
$totalCostPerMonth = 0;
|
||||||
|
|
||||||
$query = "SELECT name, price, frequency, cycle, currency_id, next_payment, payer_user_id, category_id FROM subscriptions";
|
$query = "SELECT name, price, frequency, cycle, currency_id, next_payment, payer_user_id, category_id, payment_method_id FROM subscriptions";
|
||||||
$result = $db->query($query);
|
$result = $db->query($query);
|
||||||
if ($result) {
|
if ($result) {
|
||||||
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
while ($row = $result->fetchArray(SQLITE3_ASSOC)) {
|
||||||
@ -100,11 +111,13 @@ if ($result) {
|
|||||||
$next_payment = $subscription['next_payment'];
|
$next_payment = $subscription['next_payment'];
|
||||||
$payerId = $subscription['payer_user_id'];
|
$payerId = $subscription['payer_user_id'];
|
||||||
$categoryId = $subscription['category_id'];
|
$categoryId = $subscription['category_id'];
|
||||||
|
$paymentMethodId = $subscription['payment_method_id'];
|
||||||
$originalSubscriptionPrice = getPriceConverted($price, $currency, $db);
|
$originalSubscriptionPrice = getPriceConverted($price, $currency, $db);
|
||||||
$price = getPricePerMonth($cycle, $frequency, $originalSubscriptionPrice);
|
$price = getPricePerMonth($cycle, $frequency, $originalSubscriptionPrice);
|
||||||
$totalCostPerMonth += $price;
|
$totalCostPerMonth += $price;
|
||||||
$memberCost[$payerId]['cost'] += $price;
|
$memberCost[$payerId]['cost'] += $price;
|
||||||
$categoryCost[$categoryId]['cost'] += $price;
|
$categoryCost[$categoryId]['cost'] += $price;
|
||||||
|
$paymentMethodCount[$paymentMethodId]['count'] += 1;
|
||||||
if ($price > $mostExpensiveSubscription) {
|
if ($price > $mostExpensiveSubscription) {
|
||||||
$mostExpensiveSubscription = $price;
|
$mostExpensiveSubscription = $price;
|
||||||
}
|
}
|
||||||
@ -207,6 +220,18 @@ if ($result) {
|
|||||||
|
|
||||||
$showMemberCostGraph = count($memberDataPoints) > 1;
|
$showMemberCostGraph = count($memberDataPoints) > 1;
|
||||||
|
|
||||||
|
$paymentMethodDataPoints = [];
|
||||||
|
foreach ($paymentMethodCount as $paymentMethod) {
|
||||||
|
if ($paymentMethod['count'] != 0) {
|
||||||
|
$paymentMethodDataPoints[] = [
|
||||||
|
"label" => $paymentMethod['name'],
|
||||||
|
"y" => $paymentMethod["count"],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$showPaymentMethodCountGraph = count($paymentMethodDataPoints) > 1;
|
||||||
|
|
||||||
if ($showMemberCostGraph) {
|
if ($showMemberCostGraph) {
|
||||||
?>
|
?>
|
||||||
<section class="graph">
|
<section class="graph">
|
||||||
@ -231,6 +256,17 @@ if ($result) {
|
|||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($showPaymentMethodCountGraph) {
|
||||||
|
?>
|
||||||
|
<section class="graph">
|
||||||
|
<header>
|
||||||
|
<?= translate('payment_method_split', $i18n) ?>
|
||||||
|
</header>
|
||||||
|
<canvas id="paymentMethidSplitChart" style="height: 370px; width: 100%;"></canvas>
|
||||||
|
</section>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
|
||||||
?>
|
?>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
@ -242,6 +278,7 @@ if ($result) {
|
|||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
loadGraph("categorySplitChart", <?php echo json_encode($categoryDataPoints, JSON_NUMERIC_CHECK); ?>, "<?= $code ?>", <?= $showCategoryCostGraph ?>);
|
loadGraph("categorySplitChart", <?php echo json_encode($categoryDataPoints, JSON_NUMERIC_CHECK); ?>, "<?= $code ?>", <?= $showCategoryCostGraph ?>);
|
||||||
loadGraph("memberSplitChart", <?php echo json_encode($memberDataPoints, JSON_NUMERIC_CHECK); ?>, "<?= $code ?>", <?= $showMemberCostGraph ?>);
|
loadGraph("memberSplitChart", <?php echo json_encode($memberDataPoints, JSON_NUMERIC_CHECK); ?>, "<?= $code ?>", <?= $showMemberCostGraph ?>);
|
||||||
|
loadGraph("paymentMethidSplitChart", <?php echo json_encode($paymentMethodDataPoints, JSON_NUMERIC_CHECK); ?>, "", <?= $showPaymentMethodCountGraph ?>);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
<?php
|
<?php
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user