diff --git a/res/static/img/payment_providers/bitcoin.svg b/res/static/img/payment_providers/bitcoin.svg new file mode 100644 index 0000000..04079be --- /dev/null +++ b/res/static/img/payment_providers/bitcoin.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/res/static/img/payment_providers/dogecoin.svg b/res/static/img/payment_providers/dogecoin.svg new file mode 100644 index 0000000..c435731 --- /dev/null +++ b/res/static/img/payment_providers/dogecoin.svg @@ -0,0 +1 @@ +Dogecoin (DOGE) \ No newline at end of file diff --git a/res/static/img/payment_providers/mollie.svg b/res/static/img/payment_providers/mollie.svg new file mode 100644 index 0000000..60f6adf --- /dev/null +++ b/res/static/img/payment_providers/mollie.svg @@ -0,0 +1,18 @@ + + + + + + diff --git a/res/static/img/payment_providers/monero.svg b/res/static/img/payment_providers/monero.svg new file mode 100644 index 0000000..6dd7e07 --- /dev/null +++ b/res/static/img/payment_providers/monero.svg @@ -0,0 +1 @@ +monero \ No newline at end of file diff --git a/res/static/img/payment_providers/paypal_full.svg b/res/static/img/payment_providers/paypal_full.svg new file mode 100644 index 0000000..1eaa536 --- /dev/null +++ b/res/static/img/payment_providers/paypal_full.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/svelte/src/admin_panel/InvoiceVAT.svelte b/svelte/src/admin_panel/InvoiceVAT.svelte new file mode 100644 index 0000000..0a2601d --- /dev/null +++ b/svelte/src/admin_panel/InvoiceVAT.svelte @@ -0,0 +1,166 @@ + + + + +
+

{month_str}

+
+ +
+ +
+ + {#each Object.entries(totals) as [key, tot]} + {key} ({tot.count})
+ Amount:
+ VAT:
+ {/each} + +
+ + + + + + + + + + + + + {#each invoices as row (row.id)} + + + + + + + + + {/each} + + +
TimeAmountVATCountryMethodStatus
{formatDate(row.time)}{row.country}{row.payment_method}{row.status}
+
+
+ + diff --git a/svelte/src/admin_panel/Router.svelte b/svelte/src/admin_panel/Router.svelte index 14f238d..8316910 100644 --- a/svelte/src/admin_panel/Router.svelte +++ b/svelte/src/admin_panel/Router.svelte @@ -9,6 +9,7 @@ import EmailReporters from "./EmailReporters.svelte"; import MollieSettlements from "./MollieSettlements.svelte"; import PayPalTaxes from "./PayPalTaxes.svelte"; import UserBans from "./user_bans/UserBans.svelte"; +import InvoiceVat from "./InvoiceVAT.svelte"; let pages = [ { @@ -62,6 +63,11 @@ let pages = [ title: "Paypal Taxes", icon: "paypal", component: PayPalTaxes, + }, { + path: "/admin/invoices", + title: "Invoices", + icon: "receipt", + component: InvoiceVat, }, ], }, diff --git a/svelte/src/home_page/GetStarted.svelte b/svelte/src/home_page/GetStarted.svelte index 54445a6..d864888 100644 --- a/svelte/src/home_page/GetStarted.svelte +++ b/svelte/src/home_page/GetStarted.svelte @@ -1,6 +1,6 @@ @@ -19,13 +19,13 @@ import Euro from "util/Euro.svelte"; balance is . Use the form below to top up your balance.

- + {:else}

You are currently logged in as '{window.user.username}'. Use the form below to activate prepaid on this account.

- + {/if} diff --git a/svelte/src/user_home/MollieDeposit.svelte b/svelte/src/layout/CreditDeposit.svelte similarity index 74% rename from svelte/src/user_home/MollieDeposit.svelte rename to svelte/src/layout/CreditDeposit.svelte index 8190822..571271a 100644 --- a/svelte/src/user_home/MollieDeposit.svelte +++ b/svelte/src/layout/CreditDeposit.svelte @@ -4,11 +4,13 @@ import Euro from "util/Euro.svelte"; import LoadingIndicator from "util/LoadingIndicator.svelte"; import { countries } from "country-data-list"; import { get_endpoint, get_misc_vat_rate } from "lib/PixeldrainAPI"; +import CreditDepositNav from "./CreditDepositNav.svelte"; let loading = false let amount = 20 let country: typeof countries.all[0] = null let country_input = "" +let provider: PaymentProvider = null let vat = 0 const amounts = [10, 20, 50, 100, 200, 500, 1000, 2000, 5000] @@ -19,8 +21,30 @@ onMount(() => { country_input = checkout_country set_country() } + + const checkout_provider = window.localStorage.getItem("checkout_provider") + for (const p of providers) { + if (p.name === checkout_provider) { + set_provider(p) + break + } + } }) +type PaymentProvider = { + icon: string, + name: string, + label: string, + crypto?: boolean, +}; +const providers: PaymentProvider[] = [ + {icon: "paypal_full", name: "paypal", label: "PayPal"}, + {icon: "mollie", name: "mollie", label: "Mollie"}, + {icon: "bitcoin", name: "btc", label: "Bitcoin", crypto: true}, + {icon: "dogecoin", name: "doge", label: "Dogecoin", crypto: true}, + {icon: "monero", name: "xmr", label: "Monero", crypto: true}, +] + const payment_providers = [ {icon: "paypal", name: "PayPal"}, {icon: "creditcard", name: "Credit/debit"}, @@ -69,6 +93,13 @@ const set_country = async (e?: Event) => { } } +const set_provider = (p: PaymentProvider) => { + provider = p + + // Cache the value for next checkout + window.localStorage.setItem("checkout_provider", p.name) +} + const checkout = async () => { loading = true @@ -79,7 +110,7 @@ const checkout = async () => { const form = new FormData() form.set("amount", String(amount*1e6)) - form.set("network", "mollie") + form.set("network", provider.name) form.set("country", country.alpha2) try { @@ -161,21 +192,32 @@ const format_country = (c: typeof countries.all[0]) => { {/each} - {:else} + {:else if provider === null} + -
- -
-
- Paying from - {country.emoji} - {country.name} ({vat}% VAT) -
+

Please select a payment provider

+ +
+ {#each providers as p (p.name)} + + {/each}
+ {:else} + + +

+ When paying with cryptocurrencies it is important that you pay the + exact amount stated on the order. If you pay too little, the + order fails. If you pay too much then the remaining credit will not + be added to your account. Pay close attention when sending a payment + from an online exchange, sometimes they will subtract the fees from + the amount sent which will cause the payment to fail. +

+
Please choose an amount
{#each amounts as a} @@ -237,6 +279,19 @@ const format_country = (c: typeof countries.all[0]) => { margin: 3px; } +.providers { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(10em, 1fr)); +} +.providers > button { + flex-direction: column; + justify-content: space-around; +} +.providers > button > img { + max-width: 3em; + max-height: 3em; +} + .amount_grid { max-width: 500px; gap: 4px; diff --git a/svelte/src/layout/CreditDepositNav.svelte b/svelte/src/layout/CreditDepositNav.svelte new file mode 100644 index 0000000..abda731 --- /dev/null +++ b/svelte/src/layout/CreditDepositNav.svelte @@ -0,0 +1,29 @@ + + +
+ {#if provider !== null} + + {:else if country !== null} + + {/if} +
+
+ Paying from + {country.emoji} + + {country.name} + ({vat}% VAT) + {#if provider !== null}with {provider.label}{/if} + +
+
diff --git a/svelte/src/user_home/DepositCredit.svelte b/svelte/src/user_home/DepositCredit.svelte index 8c554e5..602e6fd 100644 --- a/svelte/src/user_home/DepositCredit.svelte +++ b/svelte/src/user_home/DepositCredit.svelte @@ -1,13 +1,12 @@
- {#if checkout_success} + {#if window.location.hash === "#checkout_complete"}

Payment successful!

@@ -78,6 +69,24 @@ onMount(() => { support@pixeldrain.com.

+ {:else if window.location.hash === "#order_expired"} +
+

Order expired

+

+ This order has expired. Please create a new order on the credit deposit page. +

+
+ {:else if window.location.hash === "#order_canceled"} +
+

Order canceled

+

+ You have chosen to cancel the order. If you still want to + proceed with the order you can initiate payment again from the + deposit page. If not then + you can let the invoice expire. +

+
{/if} diff --git a/webcontroller/web_controller.go b/webcontroller/web_controller.go index 0bd5312..9ba8219 100644 --- a/webcontroller/web_controller.go +++ b/webcontroller/web_controller.go @@ -176,6 +176,7 @@ func New(r *httprouter.Router, prefix string, conf Config) (wc *WebController) { {GET, "admin/user_management" /* */, wc.serveTemplate("admin", handlerOpts{Auth: true})}, {GET, "admin/mollie_settlements" /**/, wc.serveTemplate("admin", handlerOpts{Auth: true})}, {GET, "admin/paypal_taxes" /* */, wc.serveTemplate("admin", handlerOpts{Auth: true})}, + {GET, "admin/invoices" /* */, wc.serveTemplate("admin", handlerOpts{Auth: true})}, {GET, "admin/globals" /* */, wc.serveForm(wc.adminGlobalsForm, handlerOpts{Auth: true})}, {PST, "admin/globals" /* */, wc.serveForm(wc.adminGlobalsForm, handlerOpts{Auth: true})},