custviwe
This commit is contained in:
parent
8a044653f7
commit
877a374f97
|
@ -72,7 +72,7 @@ dependencies = [
|
|||
"actix-service",
|
||||
"actix-utils",
|
||||
"ahash 0.8.3",
|
||||
"base64",
|
||||
"base64 0.21.2",
|
||||
"bitflags",
|
||||
"brotli",
|
||||
"bytes",
|
||||
|
@ -91,7 +91,7 @@ dependencies = [
|
|||
"mime",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"sha1",
|
||||
"smallvec",
|
||||
"tokio",
|
||||
|
@ -281,7 +281,7 @@ version = "0.7.6"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.10",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
@ -293,7 +293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"getrandom",
|
||||
"getrandom 0.2.10",
|
||||
"once_cell",
|
||||
"version_check",
|
||||
]
|
||||
|
@ -322,6 +322,27 @@ dependencies = [
|
|||
"alloc-no-stdlib",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android-tzdata"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.71"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
|
||||
|
||||
[[package]]
|
||||
name = "arc-bytes"
|
||||
version = "0.3.5"
|
||||
|
@ -356,6 +377,43 @@ version = "0.7.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cf46fee83e5ccffc220104713af3292ff9bc7c64c7de289f66dae8e38d826833"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener",
|
||||
"futures-core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-stripe"
|
||||
version = "0.22.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b313de0d654c4c4c46faa737b2257ce9ed79e69926aa4c734b9816be20102b2c"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"futures-util",
|
||||
"hex",
|
||||
"hmac 0.12.1",
|
||||
"http-types",
|
||||
"hyper",
|
||||
"hyper-tls",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_path_to_error",
|
||||
"serde_qs 0.10.1",
|
||||
"sha2 0.10.7",
|
||||
"smart-default",
|
||||
"smol_str",
|
||||
"thiserror",
|
||||
"time-core",
|
||||
"tokio",
|
||||
"uuid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.68"
|
||||
|
@ -422,6 +480,12 @@ dependencies = [
|
|||
"rustc-demangle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.21.2"
|
||||
|
@ -562,7 +626,7 @@ dependencies = [
|
|||
"p256",
|
||||
"parking_lot",
|
||||
"pot",
|
||||
"rand",
|
||||
"rand 0.8.5",
|
||||
"region",
|
||||
"serde",
|
||||
"sysinfo",
|
||||
|
@ -683,6 +747,19 @@ dependencies = [
|
|||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
|
||||
dependencies = [
|
||||
"android-tzdata",
|
||||
"iana-time-zone",
|
||||
"num-traits",
|
||||
"serde",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cipher"
|
||||
version = "0.3.0"
|
||||
|
@ -756,6 +833,15 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "concurrent-queue"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "62ec6771ecfa0762d24683ee5a32ad78487a3d3afdc0fb8cae19d2c5deb50b7c"
|
||||
dependencies = [
|
||||
"crossbeam-utils",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-oid"
|
||||
version = "0.6.2"
|
||||
|
@ -785,6 +871,16 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
|
@ -874,7 +970,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
|
||||
dependencies = [
|
||||
"generic-array",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -1010,7 +1106,7 @@ checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
|
|||
dependencies = [
|
||||
"der",
|
||||
"elliptic-curve",
|
||||
"hmac",
|
||||
"hmac 0.11.0",
|
||||
"signature",
|
||||
]
|
||||
|
||||
|
@ -1031,7 +1127,7 @@ dependencies = [
|
|||
"generic-array",
|
||||
"group",
|
||||
"pkcs8",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
"zeroize",
|
||||
]
|
||||
|
@ -1045,19 +1141,49 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
|
||||
dependencies = [
|
||||
"errno-dragonfly",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "errno-dragonfly"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "2.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ff"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
|
||||
dependencies = [
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
|
@ -1090,6 +1216,21 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.0"
|
||||
|
@ -1147,6 +1288,21 @@ version = "0.3.28"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
|
||||
|
||||
[[package]]
|
||||
name = "futures-lite"
|
||||
version = "1.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49a9d51ce47660b1e808d3c990b4709f2f415d928835a17dfd16991515c46bce"
|
||||
dependencies = [
|
||||
"fastrand",
|
||||
"futures-core",
|
||||
"futures-io",
|
||||
"memchr",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
"waker-fn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "futures-macro"
|
||||
version = "0.3.28"
|
||||
|
@ -1199,6 +1355,17 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.1.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.9.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.10"
|
||||
|
@ -1208,7 +1375,7 @@ dependencies = [
|
|||
"cfg-if",
|
||||
"js-sys",
|
||||
"libc",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
|
@ -1241,7 +1408,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
|
||||
dependencies = [
|
||||
"ff",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
|
@ -1303,6 +1470,18 @@ dependencies = [
|
|||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hkdf"
|
||||
version = "0.11.0"
|
||||
|
@ -1310,7 +1489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "01706d578d5c281058480e673ae4086a9f4710d8df1ad80a5b03e39ece5f886b"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"hmac",
|
||||
"hmac 0.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1323,6 +1502,15 @@ dependencies = [
|
|||
"digest 0.9.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hmac"
|
||||
version = "0.12.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
|
||||
dependencies = [
|
||||
"digest 0.10.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hpke"
|
||||
version = "0.8.0"
|
||||
|
@ -1338,7 +1526,7 @@ dependencies = [
|
|||
"hkdf",
|
||||
"p256",
|
||||
"paste",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"serde",
|
||||
"sha2 0.9.9",
|
||||
"subtle",
|
||||
|
@ -1356,6 +1544,38 @@ dependencies = [
|
|||
"itoa",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-body"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"http",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "http-types"
|
||||
version = "2.12.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6e9b187a72d63adbfba487f48095306ac823049cb504ee195541e91c7775f5ad"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"async-channel",
|
||||
"base64 0.13.1",
|
||||
"futures-lite",
|
||||
"http",
|
||||
"infer",
|
||||
"pin-project-lite",
|
||||
"rand 0.7.3",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_qs 0.8.5",
|
||||
"serde_urlencoded",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "httparse"
|
||||
version = "1.8.0"
|
||||
|
@ -1368,6 +1588,66 @@ version = "1.0.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
|
||||
|
||||
[[package]]
|
||||
name = "hyper"
|
||||
version = "0.14.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
"httpdate",
|
||||
"itoa",
|
||||
"pin-project-lite",
|
||||
"socket2",
|
||||
"tokio",
|
||||
"tower-service",
|
||||
"tracing",
|
||||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"hyper",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fad5b825842d2b38bd206f3e81d6957625fd7f0a361e345c30e01a0ae2dd613"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"windows",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ident_case"
|
||||
version = "1.0.1"
|
||||
|
@ -1394,6 +1674,32 @@ dependencies = [
|
|||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "infer"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac"
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "io-lifetimes"
|
||||
version = "1.0.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
|
||||
dependencies = [
|
||||
"hermit-abi 0.3.1",
|
||||
"libc",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "itertools"
|
||||
version = "0.10.5"
|
||||
|
@ -1445,12 +1751,19 @@ version = "0.2.146"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
|
||||
|
||||
[[package]]
|
||||
name = "lmspos"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"actix-cors",
|
||||
"actix-web",
|
||||
"async-stripe",
|
||||
"bonsaidb",
|
||||
"log",
|
||||
"serde",
|
||||
|
@ -1565,7 +1878,7 @@ checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
|
|||
dependencies = [
|
||||
"libc",
|
||||
"log",
|
||||
"wasi",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
|
@ -1575,7 +1888,25 @@ version = "0.7.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a51313c5820b0b02bd422f4b44776fbf47961755c74ce64afc73bfad10226c3"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1655,6 +1986,50 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.54"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.88"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-varint"
|
||||
version = "1.0.1"
|
||||
|
@ -1684,6 +2059,12 @@ dependencies = [
|
|||
"sha2 0.9.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking"
|
||||
version = "2.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14f2252c834a40ed9bb5422029649578e63aa341ac401f74e719dd1afda8394e"
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
|
@ -1714,7 +2095,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "7676374caaee8a325c9e7a2ae557f216c5563a171d6997b0ef8a65af35147700"
|
||||
dependencies = [
|
||||
"base64ct",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
"subtle",
|
||||
]
|
||||
|
||||
|
@ -1874,6 +2255,19 @@ dependencies = [
|
|||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.7.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
"libc",
|
||||
"rand_chacha 0.2.2",
|
||||
"rand_core 0.5.1",
|
||||
"rand_hc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
|
@ -1881,8 +2275,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
"rand_chacha 0.3.1",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1892,7 +2296,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
|
||||
dependencies = [
|
||||
"getrandom 0.1.16",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1901,7 +2314,16 @@ version = "0.6.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"getrandom 0.2.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_hc"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
|
||||
dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1979,18 +2401,64 @@ dependencies = [
|
|||
"semver",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustix"
|
||||
version = "0.37.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"errno",
|
||||
"io-lifetimes",
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ryu"
|
||||
version = "1.0.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
|
||||
dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "semver"
|
||||
version = "1.0.17"
|
||||
|
@ -2028,6 +2496,37 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_path_to_error"
|
||||
version = "0.1.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7f05c1d5476066defcdfacce1f52fc3cae3af1d3089727100c02ae92e5abbe0"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_qs"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_qs"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa"
|
||||
dependencies = [
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_urlencoded"
|
||||
version = "0.7.1"
|
||||
|
@ -2091,7 +2590,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||
checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
|
||||
dependencies = [
|
||||
"digest 0.9.0",
|
||||
"rand_core",
|
||||
"rand_core 0.6.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -2121,6 +2620,26 @@ version = "1.10.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
|
||||
|
||||
[[package]]
|
||||
name = "smart-default"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 1.0.109",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "smol_str"
|
||||
version = "0.1.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fad6c857cbab2627dcf01ec85a623ca4e7dcb5691cbaa3d7fb7653671f0d09c9"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "socket2"
|
||||
version = "0.4.9"
|
||||
|
@ -2203,6 +2722,20 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31c0432476357e58790aaa47a8efb0c5138f137343f3b5f23bd36a27e3b0a6d6"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"redox_syscall",
|
||||
"rustix",
|
||||
"windows-sys 0.48.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.2.0"
|
||||
|
@ -2240,9 +2773,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.22"
|
||||
version = "0.3.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea9e1b3cf1243ae005d9e74085d4d542f3125458f3a81af210d901dcd7411efd"
|
||||
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890"
|
||||
dependencies = [
|
||||
"itoa",
|
||||
"libc",
|
||||
|
@ -2254,15 +2787,15 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "time-core"
|
||||
version = "0.1.1"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
|
||||
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd"
|
||||
|
||||
[[package]]
|
||||
name = "time-macros"
|
||||
version = "0.2.9"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
|
||||
checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36"
|
||||
dependencies = [
|
||||
"time-core",
|
||||
]
|
||||
|
@ -2312,6 +2845,16 @@ dependencies = [
|
|||
"syn 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-util"
|
||||
version = "0.7.8"
|
||||
|
@ -2343,6 +2886,12 @@ dependencies = [
|
|||
"winnow",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
|
||||
|
||||
[[package]]
|
||||
name = "tracing"
|
||||
version = "0.1.37"
|
||||
|
@ -2404,6 +2953,12 @@ dependencies = [
|
|||
"transmog",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "try-lock"
|
||||
version = "0.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.80"
|
||||
|
@ -2475,14 +3030,51 @@ dependencies = [
|
|||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "0.8.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7"
|
||||
dependencies = [
|
||||
"getrandom 0.2.10",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "waker-fn"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca"
|
||||
|
||||
[[package]]
|
||||
name = "want"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e"
|
||||
dependencies = [
|
||||
"try-lock",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.9.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
|
@ -2586,6 +3178,15 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.48.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
|
|
|
@ -12,3 +12,4 @@ actix-web = "4"
|
|||
bonsaidb = { version = "0.4", features = ["local-full"] }
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
actix-cors = "0.6.4"
|
||||
async-stripe = { version = "0.22", features = ["runtime-tokio-hyper"] }
|
|
@ -0,0 +1,17 @@
|
|||
use std::collections::HashMap;
|
||||
use bonsaidb::core::schema::Collection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Collection, Clone)]
|
||||
#[collection(name = "customerviews")]
|
||||
pub struct CustomerView {
|
||||
pub sync_id: String,
|
||||
pub products: HashMap<CustomerViewProductSlice, u64>,
|
||||
pub price_total: f64
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct CustomerViewProductSlice {
|
||||
pub name: String,
|
||||
pub price_usd: u64
|
||||
}
|
|
@ -7,7 +7,8 @@ use serde::{Deserialize, Serialize};
|
|||
pub struct Order {
|
||||
pub order_type: OrderType,
|
||||
pub total_usd: f64,
|
||||
pub products: HashMap<u64, u64>
|
||||
pub products: HashMap<u64, u64>,
|
||||
pub stripe_status: StripeStatus
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||
|
@ -15,3 +16,11 @@ pub enum OrderType {
|
|||
Cash,
|
||||
Stripe
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||
pub enum StripeStatus {
|
||||
SessionCreated,
|
||||
Paid,
|
||||
Failed,
|
||||
NotStripeTransaction
|
||||
}
|
|
@ -1,28 +1,38 @@
|
|||
use std::error::Error;
|
||||
use actix_cors::Cors;
|
||||
use actix_web::{App, get, HttpResponse, HttpServer};
|
||||
use actix_web::{App, get, HttpRequest, HttpResponse, HttpServer};
|
||||
use actix_web::http::header::HeaderValue;
|
||||
use actix_web::web::Data;
|
||||
use bonsaidb::core::schema::Schema;
|
||||
use bonsaidb::local::AsyncDatabase;
|
||||
use bonsaidb::local::config::{Builder, StorageConfiguration};
|
||||
use stripe::Client;
|
||||
|
||||
use crate::db_products::Product;
|
||||
use crate::db_orders::Order;
|
||||
use crate::route_order::{cash_order, get_orders};
|
||||
use crate::error::APIError;
|
||||
use crate::route_customer::{custview_get, custview_push};
|
||||
use crate::db_custview::CustomerView;
|
||||
use crate::route_order::{cash_order, get_order, get_orders, stripe_order};
|
||||
use crate::route_products::{create_product, delete_product, get_product, get_products, update_product};
|
||||
use crate::route_stripe::{stripe_cancel, stripe_finish};
|
||||
|
||||
pub mod db_products;
|
||||
pub mod route_products;
|
||||
pub mod error;
|
||||
pub mod route_order;
|
||||
pub mod db_orders;
|
||||
pub mod route_stripe;
|
||||
pub mod db_custview;
|
||||
pub mod route_customer;
|
||||
|
||||
#[derive(Debug, Schema)]
|
||||
#[schema(name = "lmsposschema", collections = [Product, Order])]
|
||||
#[schema(name = "lmsposschema", collections = [Product, Order, CustomerView])]
|
||||
pub struct DbSchema;
|
||||
|
||||
pub struct AppState {
|
||||
pub db: AsyncDatabase
|
||||
pub db: AsyncDatabase,
|
||||
pub client: Client
|
||||
}
|
||||
|
||||
#[actix_web::main]
|
||||
|
@ -31,8 +41,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
let db = AsyncDatabase::open::<DbSchema>(StorageConfiguration::new("lms.bonsaidb")).await?;
|
||||
|
||||
let client = stripe::Client::new("sk_test_51HcdjVJZz7Qxr83OUKOUmzK07dLlpzmbtlUbbxptdGxdXoECKK0BfDo0F89A7A3EFLON8xQDSPxhowVlq0UF2P7000hR3OYha7");
|
||||
|
||||
let state = Data::new(AppState {
|
||||
db
|
||||
db,
|
||||
client
|
||||
});
|
||||
|
||||
HttpServer::new(move || {
|
||||
|
@ -47,8 +60,15 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||
.service(status)
|
||||
.service(get_orders)
|
||||
.service(cash_order)
|
||||
.service(stripe_order)
|
||||
.service(get_order)
|
||||
.service(stripe_cancel)
|
||||
.service(stripe_finish)
|
||||
.service(auth_status)
|
||||
.service(custview_push)
|
||||
.service(custview_get)
|
||||
})
|
||||
.bind(("127.0.0.1", 8080))?
|
||||
.bind(("0.0.0.0", 8080))?
|
||||
.run()
|
||||
.await?;
|
||||
Ok(())
|
||||
|
@ -58,3 +78,11 @@ async fn main() -> Result<(), Box<dyn Error>> {
|
|||
pub async fn status() -> HttpResponse {
|
||||
HttpResponse::Ok().body("{\"status\":\"ok\"}")
|
||||
}
|
||||
|
||||
#[get("/auth_status")]
|
||||
pub async fn auth_status(req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
HttpResponse::Ok().body("{\"status\":\"ok\"}")
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
use std::collections::HashMap;
|
||||
use actix_web::{get, HttpRequest, HttpResponse, post};
|
||||
use actix_web::http::header::HeaderValue;
|
||||
use actix_web::web::{Data, Json, Path};
|
||||
use bonsaidb::core::Error;
|
||||
use bonsaidb::core::schema::SerializedCollection;
|
||||
use log::debug;
|
||||
use serde::Deserialize;
|
||||
use crate::AppState;
|
||||
use crate::db_custview::{CustomerView, CustomerViewProductSlice};
|
||||
use crate::error::APIError;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CustviewPushReq {
|
||||
pub sync_id: String,
|
||||
pub products: HashMap<u64, (CustomerViewProductSlice, u64)>,
|
||||
pub price_total: f64
|
||||
}
|
||||
|
||||
#[post("/custview")]
|
||||
pub async fn custview_push(req: Json<CustviewPushReq>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
|
||||
let mut existing_db = match CustomerView::list_async(0.., &db.db).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||
}
|
||||
};
|
||||
|
||||
let mut converted_hashmap = HashMap::new();
|
||||
|
||||
for (k, (v, v2)) in &req.products {
|
||||
converted_hashmap.insert(v.clone(), *v2);
|
||||
}
|
||||
|
||||
for maybe_db in &mut existing_db {
|
||||
if maybe_db.contents.sync_id == req.sync_id {
|
||||
let mut definitely_db = maybe_db;
|
||||
definitely_db.contents.products = converted_hashmap.clone();
|
||||
definitely_db.contents.price_total = req.price_total;
|
||||
match definitely_db.update_async(&db.db).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||
}
|
||||
}
|
||||
return HttpResponse::Ok().finish();
|
||||
}
|
||||
}
|
||||
|
||||
let doc = CustomerView {
|
||||
sync_id: req.sync_id.clone(),
|
||||
products: converted_hashmap.clone(),
|
||||
price_total: req.price_total,
|
||||
};
|
||||
|
||||
match doc.push_into_async(&db.db).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Ok().finish()
|
||||
}
|
||||
|
||||
#[get("/custview/{id}")]
|
||||
pub async fn custview_get(id: Path<String>, db: Data<AppState>) -> HttpResponse {
|
||||
let existing_db = match CustomerView::list_async(0.., &db.db).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError { code: "DB_ERROR".to_string(), message: e.to_string() })
|
||||
}
|
||||
};
|
||||
|
||||
for maybe_db in &existing_db {
|
||||
if maybe_db.contents.sync_id == id.clone() {
|
||||
let definitely_db = maybe_db;
|
||||
|
||||
let mut translated: HashMap<u64, (CustomerViewProductSlice, u64)> = HashMap::new();
|
||||
|
||||
for (k, v) in &definitely_db.contents.products {
|
||||
translated.insert(translated.len() as u64, (k.clone(), *v));
|
||||
}
|
||||
|
||||
return HttpResponse::Ok().json(translated.clone());
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::NotFound().json(APIError { code: "Sync ID not known".to_string(), message: "Missing sync ID in DB".to_string() })
|
||||
}
|
|
@ -1,15 +1,18 @@
|
|||
use std::collections::HashMap;
|
||||
use actix_web::{get, HttpResponse, post};
|
||||
use actix_web::web::{Data, Json};
|
||||
use actix_web::{get, HttpRequest, HttpResponse, post};
|
||||
use actix_web::http::header::HeaderValue;
|
||||
use actix_web::web::{Data, Json, Path};
|
||||
use bonsaidb::core::schema::SerializedCollection;
|
||||
use log::debug;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use stripe::{CheckoutSession, CheckoutSessionMode, CreateCheckoutSession, CreateCheckoutSessionLineItems, CreateCheckoutSessionLineItemsPriceData, CreateCheckoutSessionLineItemsPriceDataProductData, Currency, Metadata};
|
||||
use crate::AppState;
|
||||
use crate::db_orders::{Order, OrderType};
|
||||
use crate::db_orders::{Order, OrderType, StripeStatus};
|
||||
use crate::db_products::Product;
|
||||
use crate::error::APIError;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct CashOrderRequest {
|
||||
pub struct OrderRequest {
|
||||
pub products: HashMap<u64, u64>,
|
||||
pub adjust_stock: bool
|
||||
}
|
||||
|
@ -20,7 +23,10 @@ pub struct CashOrderResponse {
|
|||
}
|
||||
|
||||
#[post("/cash_order")]
|
||||
pub async fn cash_order(req: Json<CashOrderRequest>, db: Data<AppState>) -> HttpResponse {
|
||||
pub async fn cash_order(req: Json<OrderRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
// load product data
|
||||
let mut products = match Product::get_multiple_async(req.products.keys(), &db.db).await {
|
||||
Ok(r) => r,
|
||||
|
@ -42,6 +48,7 @@ pub async fn cash_order(req: Json<CashOrderRequest>, db: Data<AppState>) -> Http
|
|||
order_type: OrderType::Cash,
|
||||
total_usd: price_total,
|
||||
products: req.products.clone(),
|
||||
stripe_status: StripeStatus::NotStripeTransaction
|
||||
};
|
||||
|
||||
if req.adjust_stock {
|
||||
|
@ -95,11 +102,15 @@ pub struct OrderResponse {
|
|||
pub id: u64,
|
||||
pub order_type: OrderType,
|
||||
pub total_usd: f64,
|
||||
pub products: HashMap<u64, u64>
|
||||
pub products: HashMap<u64, u64>,
|
||||
pub stripe_status: StripeStatus
|
||||
}
|
||||
|
||||
#[get("/orders")]
|
||||
pub async fn get_orders(db: Data<AppState>) -> HttpResponse {
|
||||
pub async fn get_orders(db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
let orders = match Order::list_async(0.., &db.db).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
|
@ -115,7 +126,218 @@ pub async fn get_orders(db: Data<AppState>) -> HttpResponse {
|
|||
order_type: u.contents.order_type.clone(),
|
||||
total_usd: u.contents.total_usd,
|
||||
products: u.contents.products.clone(),
|
||||
stripe_status: u.contents.stripe_status.clone()
|
||||
}).collect();
|
||||
|
||||
HttpResponse::Ok().json(OrdersResponse { orders: resp })
|
||||
}
|
||||
|
||||
#[get("/order/{id}")]
|
||||
pub async fn get_order(id: Path<u64>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
let orders = match Order::get_async(id.into_inner(), &db.db).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError {
|
||||
code: "DB_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
if let Some(u) = orders {
|
||||
HttpResponse::Ok().json(OrderResponse {
|
||||
id: u.header.id,
|
||||
order_type: u.contents.order_type.clone(),
|
||||
total_usd: u.contents.total_usd,
|
||||
products: u.contents.products.clone(),
|
||||
stripe_status: u.contents.stripe_status.clone()
|
||||
})
|
||||
} else {
|
||||
HttpResponse::NotFound().finish()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct StripeOrderResponse {
|
||||
pub order_id: u64,
|
||||
pub checkout_url: String
|
||||
}
|
||||
|
||||
#[post("/stripe_order")]
|
||||
pub async fn stripe_order(req: Json<OrderRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
// load product data
|
||||
let mut products = match Product::get_multiple_async(req.products.keys(), &db.db).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError {
|
||||
code: "DB_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let mut products_map: HashMap<u64, Product> = HashMap::new();
|
||||
for product in &products {
|
||||
products_map.insert(product.header.id, Product {
|
||||
name: product.contents.name.clone(),
|
||||
price_usd: product.contents.price_usd,
|
||||
stock: product.contents.stock,
|
||||
});
|
||||
}
|
||||
|
||||
let mut price_total: f64 = 0.0;
|
||||
|
||||
for product in &products {
|
||||
price_total += req.products[&product.header.id] as f64 * product.contents.price_usd;
|
||||
}
|
||||
|
||||
if req.adjust_stock {
|
||||
for product in &mut products {
|
||||
if product.contents.stock < req.products[&product.header.id] {
|
||||
return HttpResponse::BadRequest().json(APIError {
|
||||
code: "NOT_ENOUGH_STOCK".to_string(),
|
||||
message: "Cannot sell more items than are in stock backend".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate the stripe fee
|
||||
let f_fixed = 0.30;
|
||||
let f_percent = 0.029;
|
||||
let p_charge = (price_total + f_fixed) / (1f64 - f_percent);
|
||||
let stripe_fee = p_charge - price_total;
|
||||
|
||||
debug!("Stripe transactional fee: {} for a {} total", stripe_fee, price_total);
|
||||
|
||||
// Create line items
|
||||
|
||||
let mut products_filtered = vec![];
|
||||
for (product_id, product_qty) in &req.products {
|
||||
if *product_qty != 0 {
|
||||
products_filtered.push((*product_id, *product_qty));
|
||||
}
|
||||
}
|
||||
|
||||
let line_items = products_filtered.iter().map(|(id, qty)| {
|
||||
CreateCheckoutSessionLineItems {
|
||||
adjustable_quantity: None,
|
||||
dynamic_tax_rates: None,
|
||||
price: None,
|
||||
price_data: Some(CreateCheckoutSessionLineItemsPriceData {
|
||||
currency: Currency::USD,
|
||||
product: None,
|
||||
product_data: Some(CreateCheckoutSessionLineItemsPriceDataProductData {
|
||||
description: None,
|
||||
images: None,
|
||||
metadata: Metadata::from([
|
||||
("X-LMSPOS-ID".to_string(), id.to_string())
|
||||
]),
|
||||
name: products_map[id].name.clone(),
|
||||
tax_code: None,
|
||||
}),
|
||||
recurring: None,
|
||||
tax_behavior: None,
|
||||
unit_amount: Some((products_map[id].price_usd * 100f64) as i64),
|
||||
unit_amount_decimal: None,
|
||||
}),
|
||||
quantity: Some(*qty),
|
||||
tax_rates: None,
|
||||
}
|
||||
}).collect();
|
||||
|
||||
let doc = Order {
|
||||
order_type: OrderType::Stripe,
|
||||
total_usd: price_total,
|
||||
products: req.products.clone(),
|
||||
stripe_status: StripeStatus::SessionCreated
|
||||
};
|
||||
|
||||
let order = match doc.push_into_async(&db.db).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError {
|
||||
code: "DB_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
let checkout_session = CheckoutSession::create(&db.client, CreateCheckoutSession {
|
||||
after_expiration: None,
|
||||
allow_promotion_codes: None,
|
||||
automatic_tax: None,
|
||||
billing_address_collection: None,
|
||||
cancel_url: Some(&format!("http://192.168.254.201:8080/stripe_cancel?session_id={{CHECKOUT_SESSION_ID}}&order={}", order.header.id)),
|
||||
client_reference_id: None,
|
||||
consent_collection: None,
|
||||
currency: None,
|
||||
custom_fields: None,
|
||||
custom_text: None,
|
||||
customer: None,
|
||||
customer_creation: None,
|
||||
customer_email: None,
|
||||
customer_update: None,
|
||||
discounts: None,
|
||||
expand: &[],
|
||||
expires_at: None,
|
||||
invoice_creation: None,
|
||||
line_items: Some(line_items),
|
||||
locale: None,
|
||||
metadata: Some(Metadata::from([
|
||||
("X-LMSPOS-Affects-Stock".to_string(), req.adjust_stock.to_string())
|
||||
])),
|
||||
mode: Some(CheckoutSessionMode::Payment),
|
||||
payment_intent_data: None,
|
||||
payment_method_collection: None,
|
||||
payment_method_options: None,
|
||||
payment_method_types: None,
|
||||
phone_number_collection: None,
|
||||
setup_intent_data: None,
|
||||
shipping_address_collection: None,
|
||||
shipping_options: None,
|
||||
shipping_rates: None,
|
||||
submit_type: None,
|
||||
subscription_data: None,
|
||||
success_url: &format!("http://192.168.254.201:8080/stripe_finish?session_id={{CHECKOUT_SESSION_ID}}&order={}", order.header.id),
|
||||
tax_id_collection: None,
|
||||
});
|
||||
|
||||
let session = match checkout_session.await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError {
|
||||
code: "STRIPE_ERR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
debug!("Payment session created! ID: {}", session.id);
|
||||
|
||||
if req.adjust_stock {
|
||||
for product in &mut products {
|
||||
product.contents.stock -= req.products[&product.header.id];
|
||||
match product.update_async(&db.db).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
return HttpResponse::InternalServerError().json(APIError {
|
||||
code: "DB_ERROR".to_string(),
|
||||
message: e.to_string(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Ok().json(StripeOrderResponse {
|
||||
order_id: order.header.id,
|
||||
checkout_url: session.url.unwrap(),
|
||||
})
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
use actix_web::{get, post, HttpResponse, put, delete};
|
||||
use actix_web::{get, post, HttpResponse, put, delete, HttpRequest};
|
||||
use actix_web::http::header::HeaderValue;
|
||||
use actix_web::web::{Data, Json, Path};
|
||||
use bonsaidb::core::schema::SerializedCollection;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -20,7 +21,10 @@ pub struct ProductResponse {
|
|||
}
|
||||
|
||||
#[get("/products")]
|
||||
pub async fn get_products(db: Data<AppState>) -> HttpResponse {
|
||||
pub async fn get_products(db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
let products = match Product::list_async(0.., &db.db).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
|
@ -37,7 +41,10 @@ pub async fn get_products(db: Data<AppState>) -> HttpResponse {
|
|||
}
|
||||
|
||||
#[get("/products/{id}")]
|
||||
pub async fn get_product(id: Path<u64>, db: Data<AppState>) -> HttpResponse {
|
||||
pub async fn get_product(id: Path<u64>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
let product = match Product::get_async(id.into_inner(), &db.db).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
|
@ -71,7 +78,10 @@ pub struct CreateProductRequest {
|
|||
}
|
||||
|
||||
#[post("/products")]
|
||||
pub async fn create_product(req: Json<CreateProductRequest>, db: Data<AppState>) -> HttpResponse {
|
||||
pub async fn create_product(req: Json<CreateProductRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
let document = Product {
|
||||
name: req.name.clone(),
|
||||
price_usd: req.price_usd,
|
||||
|
@ -103,7 +113,10 @@ pub struct UpdateProductRequest {
|
|||
}
|
||||
|
||||
#[put("/products/{id}")]
|
||||
pub async fn update_product(id: Path<u64>, req: Json<CreateProductRequest>, db: Data<AppState>) -> HttpResponse {
|
||||
pub async fn update_product(id: Path<u64>, req: Json<CreateProductRequest>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
let document = match Product::get_async(id.into_inner(), &db.db).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
|
@ -144,7 +157,10 @@ pub async fn update_product(id: Path<u64>, req: Json<CreateProductRequest>, db:
|
|||
}
|
||||
|
||||
#[delete("/products/{id}")]
|
||||
pub async fn delete_product(id: Path<u64>, db: Data<AppState>) -> HttpResponse {
|
||||
pub async fn delete_product(id: Path<u64>, db: Data<AppState>, req_info: HttpRequest) -> HttpResponse {
|
||||
if req_info.headers().get("Authorization") != Some(&HeaderValue::from_str("Bearer 65ed1563-b9a3-4923-8f5a-a0ea955adf97").unwrap()) {
|
||||
return HttpResponse::Unauthorized().json(APIError { code: "UNAUTHORIZED".to_string(), message: "Unauthorized".to_string() });
|
||||
}
|
||||
let document = match Product::get_async(id.into_inner(), &db.db).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
|
|
|
@ -0,0 +1,135 @@
|
|||
use std::str::FromStr;
|
||||
use actix_web::{get, HttpResponse};
|
||||
use actix_web::web::{Data, Path, Query};
|
||||
use bonsaidb::core::schema::SerializedCollection;
|
||||
use log::error;
|
||||
use serde::Deserialize;
|
||||
use stripe::{CheckoutSession, CheckoutSessionId, CheckoutSessionPaymentStatus};
|
||||
use crate::AppState;
|
||||
use crate::db_orders::{Order, StripeStatus};
|
||||
use crate::db_products::Product;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
pub struct StripeCancelQuery {
|
||||
session_id: String,
|
||||
order: u64
|
||||
}
|
||||
|
||||
#[get("/stripe_cancel")]
|
||||
pub async fn stripe_cancel(req: Query<StripeCancelQuery>, db: Data<AppState>) -> HttpResponse {
|
||||
// lookup order ID
|
||||
let order = match Order::get_async(req.order, &db.db).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||
}
|
||||
};
|
||||
|
||||
let order = match order {
|
||||
Some(o) => o,
|
||||
None => {
|
||||
return HttpResponse::NotFound().body("We were unable to find your order in our systems. Please try again later.")
|
||||
}
|
||||
};
|
||||
|
||||
// make sure the order isnt over yet
|
||||
if order.contents.stripe_status != StripeStatus::SessionCreated {
|
||||
return HttpResponse::BadRequest().body("This transaction has already been finished or cancelled. Please try again later.")
|
||||
}
|
||||
|
||||
// cancel the order in our database
|
||||
let mut order = order;
|
||||
order.contents.stripe_status = StripeStatus::Failed;
|
||||
match order.update_async(&db.db).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||
}
|
||||
}
|
||||
|
||||
// lookup and cancel the order in stripe - do we need to un-adjust stock?
|
||||
let session = match CheckoutSession::expire(&db.client, &CheckoutSessionId::from_str(&req.session_id).unwrap()).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||
}
|
||||
};
|
||||
|
||||
let need_unadjust_stock = session.metadata.get("X-LMSPOS-Affects-Stock") == Some(&String::from("true"));
|
||||
|
||||
if need_unadjust_stock {
|
||||
let mut products = match Product::get_multiple_async(order.contents.products.keys(), &db.db).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.");
|
||||
}
|
||||
};
|
||||
|
||||
for product in &mut products {
|
||||
product.contents.stock += order.contents.products[&product.header.id];
|
||||
match product.update_async(&db.db).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Ok().body("Your order has been cancelled. We hope to see you again soon!")
|
||||
}
|
||||
|
||||
#[get("/stripe_finish")]
|
||||
pub async fn stripe_finish(req: Query<StripeCancelQuery>, db: Data<AppState>) -> HttpResponse {
|
||||
// lookup order ID
|
||||
let order = match Order::get_async(req.order, &db.db).await {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||
}
|
||||
};
|
||||
|
||||
let order = match order {
|
||||
Some(o) => o,
|
||||
None => {
|
||||
return HttpResponse::NotFound().body("We were unable to find your order in our systems. Please try again later.")
|
||||
}
|
||||
};
|
||||
|
||||
// make sure the order isnt over yet
|
||||
if order.contents.stripe_status != StripeStatus::SessionCreated {
|
||||
return HttpResponse::BadRequest().body("This transaction has already been finished or cancelled. Please try again later.")
|
||||
}
|
||||
|
||||
// lookup the order in stripe
|
||||
let session = match CheckoutSession::retrieve(&db.client, &CheckoutSessionId::from_str(&req.session_id).unwrap(), &[]).await {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||
}
|
||||
};
|
||||
|
||||
if session.payment_status != CheckoutSessionPaymentStatus::Paid {
|
||||
return HttpResponse::BadRequest().body("This transaction has not yet been paid. Please try again later.")
|
||||
}
|
||||
|
||||
// finish the order in our database
|
||||
let mut order = order;
|
||||
order.contents.stripe_status = StripeStatus::Paid;
|
||||
match order.update_async(&db.db).await {
|
||||
Ok(_) => (),
|
||||
Err(e) => {
|
||||
error!("{}", e);
|
||||
return HttpResponse::InternalServerError().body("There was an error completing your request. Please try again later.")
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse::Ok().body("Thank you for your order! Payment has been initiated and your transaction has been completed. We hope to see you again soon!")
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
import { persist } from "$lib/PersistentStore";
|
||||
|
||||
export const authToken = persist("auth", "YOUR_TOKEN_HERE");
|
|
@ -11,6 +11,10 @@
|
|||
import HelperText from "@smui/textfield/helper-text";
|
||||
import Checkbox from "@smui/checkbox";
|
||||
import FormField from "@smui/form-field";
|
||||
import CircularProgress from "@smui/circular-progress";
|
||||
import QRJS from "$lib/components/QRJS.svelte";
|
||||
import {authToken} from "$lib/stores/AuthStore";
|
||||
import {browser} from "$app/environment";
|
||||
|
||||
let products = [];
|
||||
let productsCounter = {};
|
||||
|
@ -28,7 +32,7 @@
|
|||
async function loadProducts() {
|
||||
loaded = false;
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/products`);
|
||||
let resp = await fetch(`${$serverUrl}/products`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||
if (resp.ok) {
|
||||
let json = await resp.json();
|
||||
console.log(json);
|
||||
|
@ -147,7 +151,8 @@
|
|||
let resp = await fetch(`${$serverUrl}/cash_order`, {
|
||||
method: 'POST',
|
||||
headers: [
|
||||
['Content-Type', 'application/json']
|
||||
['Content-Type', 'application/json'],
|
||||
["Authorization", "Bearer " + $authToken]
|
||||
],
|
||||
body: JSON.stringify({
|
||||
products: productsCounter,
|
||||
|
@ -174,6 +179,222 @@
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let stripeOpen = false;
|
||||
let stripeTransactionFinished = false;
|
||||
let stripeTransactionStarted = false;
|
||||
|
||||
let stripeProgressSpinner = false;
|
||||
let stripeProgressSpinnerText = "";
|
||||
let stripeProgressSpinnerClosed = false;
|
||||
|
||||
let stripeCanClose = false;
|
||||
function updateCanClose() {
|
||||
stripeCanClose = !stripeTransactionFinished;
|
||||
}
|
||||
$: stripeTransactionFinished, updateCanClose();
|
||||
|
||||
let hasStripeUrl = false;
|
||||
|
||||
let order_url = '';
|
||||
|
||||
async function startStripeTransaction() {
|
||||
stripeTransactionStarted = true;
|
||||
|
||||
stripeProgressSpinner = true;
|
||||
stripeProgressSpinnerText = "Contacting Stripe API to initiate transaction...";
|
||||
|
||||
let order_id = '';
|
||||
|
||||
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/stripe_order`, {
|
||||
method: 'POST',
|
||||
headers: [
|
||||
['Content-Type', 'application/json'],
|
||||
["Authorization", "Bearer " + $authToken]
|
||||
],
|
||||
body: JSON.stringify({
|
||||
products: productsCounter,
|
||||
adjust_stock: adjustStockOnOrderFinish
|
||||
})
|
||||
});
|
||||
if (resp.ok) {
|
||||
let json = await resp.json();
|
||||
loadedCashIn = true;
|
||||
snackbarText = "Order started! Order ID: " + json.order_id;
|
||||
console.log(json);
|
||||
|
||||
order_url = json.checkout_url;
|
||||
order_id = json.order_id;
|
||||
|
||||
hasStripeUrl = true;
|
||||
|
||||
snackbar.open();
|
||||
} else {
|
||||
console.error(await resp.text());
|
||||
snackbarText = "There was an error starting the order. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
|
||||
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||
stripeProgressSpinnerClosed = true;
|
||||
stripeTransactionFinished = true;
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
snackbarText = "There was an error starting the order. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
|
||||
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||
stripeProgressSpinnerClosed = true;
|
||||
stripeTransactionFinished = true;
|
||||
return;
|
||||
}
|
||||
|
||||
stripeProgressSpinnerText = "Waiting for customer...";
|
||||
|
||||
async function updateOrderStatus() {
|
||||
console.log('polling for updated stripe order info');
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/order/${order_id}`, {
|
||||
method: 'GET',
|
||||
headers: [["Authorization", "Bearer " + $authToken]]
|
||||
});
|
||||
if (resp.ok) {
|
||||
let json = await resp.json();
|
||||
|
||||
if (json.stripe_status === 'SessionCreated') {
|
||||
console.log('result: SessionCreated waiting for customer');
|
||||
setTimeout(updateOrderStatus, 1000);
|
||||
return;
|
||||
} else if (json.stripe_status === 'Paid') {
|
||||
hasStripeUrl = false;
|
||||
console.log('result: Paid order complete');
|
||||
stripeProgressSpinnerText = 'Order complete! Payment was successful.';
|
||||
stripeProgressSpinnerClosed = true;
|
||||
stripeTransactionFinished = true;
|
||||
snackbarText = "Order complete! Order ID: " + json.id;
|
||||
snackbar.open();
|
||||
return;
|
||||
} else {
|
||||
hasStripeUrl = false;
|
||||
console.log('result: Other order cancelled');
|
||||
stripeProgressSpinnerText = 'Order cancelled by customer or payment provider';
|
||||
stripeProgressSpinnerClosed = true;
|
||||
stripeTransactionFinished = true;
|
||||
snackbarText = "Order cancelled! Order ID: " + json.id;
|
||||
snackbar.open();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
hasStripeUrl = false;
|
||||
console.error(await resp.text());
|
||||
snackbarText = "There was an error checking the order status. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
|
||||
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||
stripeProgressSpinnerClosed = true;
|
||||
stripeTransactionFinished = true;
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
hasStripeUrl = false;
|
||||
console.error(e);
|
||||
snackbarText = "There was an error checking the order status. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
|
||||
stripeProgressSpinnerText = "Transaction failed. Check browser console for more information.";
|
||||
stripeProgressSpinnerClosed = true;
|
||||
stripeTransactionFinished = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await updateOrderStatus();
|
||||
}
|
||||
|
||||
function openStripe() {
|
||||
stripeTransactionFinished = false;
|
||||
stripeTransactionStarted = false;
|
||||
|
||||
stripeProgressSpinner = false;
|
||||
stripeProgressSpinnerText = "";
|
||||
stripeProgressSpinnerClosed = false;
|
||||
|
||||
stripeOpen = true;
|
||||
}
|
||||
|
||||
|
||||
function uuid() {
|
||||
var uuid = "", i, random;
|
||||
for (i = 0; i < 32; i++) {
|
||||
random = Math.random() * 16 | 0;
|
||||
|
||||
if (i == 8 || i == 12 || i == 16 || i == 20) {
|
||||
uuid += "-"
|
||||
}
|
||||
uuid += (i == 12 ? 4 : (i == 16 ? (random & 3 | 8) : random)).toString(16);
|
||||
}
|
||||
return uuid;
|
||||
}
|
||||
|
||||
let cs_view_sync_code = uuid();
|
||||
let showCsQrCode = false;
|
||||
let csQrCodeUrl = "";
|
||||
|
||||
onMount(() => {
|
||||
csQrCodeUrl = `${window.location}customer?cs=${cs_view_sync_code}`;
|
||||
});
|
||||
|
||||
async function resendCs() {
|
||||
if (!browser) return;
|
||||
|
||||
let product_slice = {};
|
||||
|
||||
for (let i = 0; i < products.length; i++) {
|
||||
let product = products[i];
|
||||
let counter = productsCounter[product.id];
|
||||
|
||||
product_slice[product.id] = [
|
||||
{
|
||||
name: `${product.name} (#${product.id})`,
|
||||
price_usd: Math.trunc(product.price_usd * 100)
|
||||
},
|
||||
counter
|
||||
]
|
||||
}
|
||||
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/custview`, {
|
||||
method: 'POST',
|
||||
headers: [
|
||||
['Content-Type', 'application/json'],
|
||||
["Authorization", "Bearer " + $authToken]
|
||||
],
|
||||
body: JSON.stringify({
|
||||
sync_id: cs_view_sync_code,
|
||||
products: product_slice,
|
||||
price_total: total
|
||||
})
|
||||
});
|
||||
if (!resp.ok) {
|
||||
console.error(await resp.text());
|
||||
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
$: productsCounter, resendCs();
|
||||
</script>
|
||||
|
||||
<Header selected="pos" />
|
||||
|
@ -234,7 +455,7 @@
|
|||
<Button disabled={!hasProducts} variant="outlined" on:click={() => {cashIn = total.toFixed(2); cashDialogOpen = true;}}>
|
||||
<ButtonLabel>Cash In</ButtonLabel>
|
||||
</Button>
|
||||
<Button disabled={!hasProducts} variant="outlined">
|
||||
<Button disabled={!hasProducts} variant="outlined" on:click={() => {openStripe()}}>
|
||||
<ButtonLabel>Stripe</ButtonLabel>
|
||||
</Button>
|
||||
<Button variant="unelevated" on:click={() => {for (let i = 0; i < products.length; i++) {productsCounter[products[i].id] = 0}}}>
|
||||
|
@ -248,6 +469,19 @@
|
|||
<LinearProgress indeterminate bind:closed={loaded} aria-label="Data is being loaded..." slot="progress" />
|
||||
</DataTable>
|
||||
|
||||
<Textfield label="Customer View Sync Code" bind:value={cs_view_sync_code}></Textfield>
|
||||
<Button on:click={() => {showCsQrCode = true}}>
|
||||
<ButtonLabel>Open Customer View</ButtonLabel>
|
||||
</Button>
|
||||
|
||||
<Dialog bind:open={showCsQrCode} aria-labelledby="cs-title" aria-describedby="cs-content">
|
||||
<DialogTitle id="cs-title">Customer View QR Code</DialogTitle>
|
||||
<DialogContent id="cs-content">
|
||||
Use this QR code on another device to open the Customer View.
|
||||
<QRJS codeValue="" squareSize="200" />
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
|
||||
<Dialog bind:open={cashDialogOpen} aria-labelledby="cash-title" aria-describedby="cash-content">
|
||||
<DialogTitle id="cash-title">Cash In</DialogTitle>
|
||||
<DialogContent id="cash-content">
|
||||
|
@ -294,3 +528,34 @@
|
|||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
||||
|
||||
<Dialog bind:open={stripeOpen} aria-labelledby="stripe-title" aria-describedby="stripe-content" scrimClickAction="" escapeKeyAction="">
|
||||
<DialogTitle id="stripe-title">Stripe Transaction</DialogTitle>
|
||||
<DialogContent id="stripe-content">
|
||||
<p>Total Price: {formatter.format(total)}</p>
|
||||
<p>Stripe transactions cannot be stopped once started. Confirm with customer now before starting the transaction.</p>
|
||||
<Button bind:disabled={stripeTransactionStarted} on:click={startStripeTransaction}>
|
||||
<ButtonLabel>Start Transaction</ButtonLabel>
|
||||
</Button>
|
||||
{#if hasStripeUrl}
|
||||
<QRJS squareSize="200" codeValue="{order_url}" />
|
||||
<Button on:click={() => {window.open(order_url, "_blank")}}>
|
||||
<ButtonLabel>Card In Hand?</ButtonLabel>
|
||||
</Button>
|
||||
{/if}
|
||||
{#if stripeProgressSpinner}
|
||||
<div style="display: flex; margin-top: 5px;">
|
||||
<CircularProgress bind:closed={stripeProgressSpinnerClosed} style="height: 32px; width: 32px; margin-right: 5px;" indeterminate />
|
||||
<span style="margin-top: 3px;">{stripeProgressSpinnerText}</span>
|
||||
</div>
|
||||
{/if}
|
||||
</DialogContent>
|
||||
<DialogActions>
|
||||
<Button bind:disabled={stripeCanClose}>
|
||||
<ButtonLabel>Finish</ButtonLabel>
|
||||
</Button>
|
||||
<Button bind:disabled={stripeTransactionStarted}>
|
||||
<ButtonLabel>Cancel</ButtonLabel>
|
||||
</Button>
|
||||
</DialogActions>
|
||||
</Dialog>
|
|
@ -0,0 +1,96 @@
|
|||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import {serverUrl} from "$lib/stores/ServerStore";
|
||||
import Snackbar, {Label as SnackbarLabel} from "@smui/snackbar";
|
||||
import DataTable, { Head, Body, Row, Cell } from '@smui/data-table';
|
||||
import LinearProgress from "@smui/linear-progress";
|
||||
|
||||
let snackbar: Snackbar;
|
||||
let snackbarText = "";
|
||||
|
||||
let csCode = '';
|
||||
|
||||
let csData = {};
|
||||
let data = [];
|
||||
|
||||
const formatter = new Intl.NumberFormat('en-US', {style: 'currency', currency: 'USD'});
|
||||
|
||||
let loaded = false;
|
||||
|
||||
let total = 0.0;
|
||||
|
||||
async function updateData() {
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/custview/${csCode}`);
|
||||
if (resp.ok) {
|
||||
csData = await resp.json();
|
||||
console.log(csData);
|
||||
|
||||
data = Object.entries(csData);
|
||||
|
||||
setTimeout(updateData, 500);
|
||||
loaded = true;
|
||||
} else {
|
||||
console.error(await resp.text());
|
||||
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
loaded = true;
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
snackbarText = "There was an error updating the customer view. Check the browser console for more information.";
|
||||
snackbar.open();
|
||||
loaded = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
onMount(() => {
|
||||
const params = new URLSearchParams(window.location.search);
|
||||
if (!params.has("cs")) {
|
||||
snackbarText = "CS code missing. Please scan your QR code again.";
|
||||
snackbar.open();
|
||||
return;
|
||||
}
|
||||
csCode = params.get("cs");
|
||||
updateData();
|
||||
})
|
||||
</script>
|
||||
|
||||
<Snackbar bind:this={snackbar}>
|
||||
<SnackbarLabel>{snackbarText}</SnackbarLabel>
|
||||
</Snackbar>
|
||||
|
||||
<DataTable table$aria-label="Product list" style="width: 100%;">
|
||||
<Head>
|
||||
<Row>
|
||||
<Cell>Name</Cell>
|
||||
<Cell>Price Ea</Cell>
|
||||
<Cell>Qty</Cell>
|
||||
<Cell>Price</Cell>
|
||||
</Row>
|
||||
</Head>
|
||||
<Body>
|
||||
{#each data as [num, data]}
|
||||
{#if data[1] !== 0}
|
||||
<Row>
|
||||
<Cell>{data[0].name}</Cell>
|
||||
<Cell>{formatter.format(data[0].price_usd / 100)}</Cell>
|
||||
<Cell>{data[1]}</Cell>
|
||||
<Cell>{formatter.format(data[0].price_usd * data[1] / 100)}</Cell>
|
||||
</Row>
|
||||
{/if}
|
||||
{/each}
|
||||
<Row>
|
||||
<Cell numeric></Cell>
|
||||
<Cell></Cell>
|
||||
<Cell><b>Total</b></Cell>
|
||||
<Cell>
|
||||
{formatter.format(total)}
|
||||
</Cell>
|
||||
</Row>
|
||||
</Body>
|
||||
|
||||
<LinearProgress indeterminate bind:closed={loaded} aria-label="Data is being loaded..." slot="progress" />
|
||||
</DataTable>
|
|
@ -8,6 +8,7 @@
|
|||
import {serverUrl} from "$lib/stores/ServerStore";
|
||||
|
||||
import Snackbar from "@smui/snackbar";
|
||||
import {authToken} from "$lib/stores/AuthStore";
|
||||
|
||||
let snackbarTesting: Snackbar;
|
||||
let snackbarTestSuccess: Snackbar;
|
||||
|
@ -36,6 +37,10 @@
|
|||
snackbarTestFailure.open();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
authTokenTesting.close();
|
||||
authTokenTestFailure.open();
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
|
@ -44,6 +49,46 @@
|
|||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let authTokenTesting: Snackbar;
|
||||
let authTokenTestSuccess: Snackbar;
|
||||
let authTokenTestFailure: Snackbar;
|
||||
let changeAuthTokenOpen = false;
|
||||
|
||||
let changeAuthTokenFocused;
|
||||
let changeAuthTokenDirty;
|
||||
let newAuthToken = $authToken;
|
||||
let changeAuthTokenInvalid;
|
||||
|
||||
async function testAuthTokenConnection() {
|
||||
authTokenTesting.open();
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/auth_status`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||
if (resp.ok) {
|
||||
let json = await resp.json();
|
||||
if (json.status === "ok") {
|
||||
// ok!
|
||||
authTokenTesting.close();
|
||||
authTokenTestSuccess.open();
|
||||
return;
|
||||
} else {
|
||||
console.error("Response .status was not ok");
|
||||
authTokenTesting.close();
|
||||
authTokenTestFailure.open();
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
authTokenTesting.close();
|
||||
authTokenTestFailure.open();
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
authTokenTesting.close();
|
||||
authTokenTestFailure.open();
|
||||
return;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Header selected="manage/env" />
|
||||
|
@ -62,6 +107,20 @@
|
|||
</PaperContent>
|
||||
</Paper>
|
||||
|
||||
<Paper>
|
||||
<PaperTitle>Authentication Token</PaperTitle>
|
||||
<PaperSubtitle>Configure the token that LMSPOS uses to authenticate with the backend.</PaperSubtitle>
|
||||
<PaperContent>
|
||||
<p>Current: <pre>{$authToken}</pre>
|
||||
<Button variant="raised" on:click={() => {changeAuthTokenOpen = true}}>
|
||||
<Label>Change</Label>
|
||||
</Button>
|
||||
<Button variant="outlined" on:click={testAuthTokenConnection}>
|
||||
<Label>Test</Label>
|
||||
</Button>
|
||||
</PaperContent>
|
||||
</Paper>
|
||||
|
||||
<Snackbar bind:this={snackbarTesting}>
|
||||
<Label>Testing server connection, this may take a moment...</Label>
|
||||
</Snackbar>
|
||||
|
@ -72,6 +131,16 @@
|
|||
<Label>Connection failed. Check browser console for details.</Label>
|
||||
</Snackbar>
|
||||
|
||||
<Snackbar bind:this={authTokenTesting}>
|
||||
<Label>Testing server connection with auth token, this may take a moment...</Label>
|
||||
</Snackbar>
|
||||
<Snackbar bind:this={authTokenTestSuccess}>
|
||||
<Label>Connection successful!</Label>
|
||||
</Snackbar>
|
||||
<Snackbar bind:this={authTokenTestFailure}>
|
||||
<Label>Connection failed. Check browser console for details.</Label>
|
||||
</Snackbar>
|
||||
|
||||
<Dialog bind:open={changeServerUrlOpen} aria-labelledby="change-title" aria-describedby="change-content">
|
||||
<DialogTitle id="change-title">Change server URL</DialogTitle>
|
||||
<DialogContent id="change-content">
|
||||
|
@ -91,3 +160,19 @@
|
|||
</Button>
|
||||
</Actions>
|
||||
</Dialog>
|
||||
|
||||
<Dialog bind:open={changeAuthTokenOpen} aria-labelledby="token-title" aria-describedby="token-content">
|
||||
<DialogTitle id="token-title">Change auth token</DialogTitle>
|
||||
<DialogContent id="token-content">
|
||||
This is the token that LMSPOS will use to connect to it's backend. It is <i>highly recommended</i> that you use the "Test" button to ensure this is working properly before proceeding. <br>
|
||||
<Textfield type="text" bind:dirty={changeAuthTokenDirty} bind:invalid={changeAuthTokenInvalid} updateInvalid bind:value={newAuthToken} label="Auth Token" on:focus={() => {changeAuthTokenFocused = true}} on:blur={() => {changeAuthTokenFocused = false}}></Textfield>
|
||||
</DialogContent>
|
||||
<Actions>
|
||||
<Button on:click={() => {authToken.set(newAuthToken); window.location.reload();}}>
|
||||
<Label>Save</Label>
|
||||
</Button>
|
||||
<Button on:click={() => {changeAuthTokenOpen = false; newAuthToken = $authToken;}}>
|
||||
<Label>Cancel</Label>
|
||||
</Button>
|
||||
</Actions>
|
||||
</Dialog>
|
|
@ -6,6 +6,7 @@
|
|||
import { onMount } from 'svelte';
|
||||
import {serverUrl} from "$lib/stores/ServerStore";
|
||||
import Paper, { Title as PaperTitle, Content as PaperContent } from "@smui/paper";
|
||||
import {authToken} from "$lib/stores/AuthStore";
|
||||
|
||||
let loaded = false;
|
||||
let orders = [];
|
||||
|
@ -18,7 +19,7 @@
|
|||
async function loadOrders() {
|
||||
loaded = false;
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/orders`);
|
||||
let resp = await fetch(`${$serverUrl}/orders`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||
if (resp.ok) {
|
||||
let json = await resp.json();
|
||||
console.log(json);
|
||||
|
@ -45,7 +46,7 @@
|
|||
async function loadProducts() {
|
||||
loaded = false;
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/products`);
|
||||
let resp = await fetch(`${$serverUrl}/products`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||
if (resp.ok) {
|
||||
let json = await resp.json();
|
||||
console.log(json);
|
||||
|
@ -108,6 +109,10 @@
|
|||
let stripe_orders = 0;
|
||||
let cash_orders = 0;
|
||||
|
||||
let stripe_sessioncreated = 0;
|
||||
let stripe_failed = 0;
|
||||
let stripe_paid = 0;
|
||||
|
||||
function updateStats() {
|
||||
for (let i = 0; i < orders.length; i++) {
|
||||
if (orders[i].order_type === "Cash") {
|
||||
|
@ -115,6 +120,13 @@
|
|||
}
|
||||
if (orders[i].order_type === "Stripe") {
|
||||
stripe_orders += 1;
|
||||
if (orders[i].stripe_status === 'SessionCreated') {
|
||||
stripe_sessioncreated += 1;
|
||||
} else if (orders[i].stripe_status === 'Failed') {
|
||||
stripe_failed += 1;
|
||||
} else if (orders[i].stripe_status === 'Paid') {
|
||||
stripe_paid += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,6 +143,7 @@
|
|||
<Cell numeric>ID</Cell>
|
||||
<Cell style="width: 70%;">Products</Cell>
|
||||
<Cell>Order Type</Cell>
|
||||
<Cell>Stripe Status</Cell>
|
||||
<Cell>Revenue</Cell>
|
||||
</Row>
|
||||
</Head>
|
||||
|
@ -142,6 +155,7 @@
|
|||
{buildProductsString(order)}
|
||||
</Cell>
|
||||
<Cell>{order.order_type}</Cell>
|
||||
<Cell>{order.stripe_status}</Cell>
|
||||
<Cell>{formatter.format(order.total_usd)}</Cell>
|
||||
</Row>
|
||||
{/each}
|
||||
|
@ -149,6 +163,7 @@
|
|||
<Row>
|
||||
<Cell numeric></Cell>
|
||||
<Cell></Cell>
|
||||
<Cell></Cell>
|
||||
<Cell><b>Total Revenue</b></Cell>
|
||||
<Cell>{formatter.format(total.toFixed(2))}</Cell>
|
||||
</Row>
|
||||
|
@ -165,6 +180,9 @@
|
|||
<p>order_type = STRIPE: {stripe_orders}</p>
|
||||
<p>Percentage of orders using CASH: {(cash_orders / orders.length) * 100}%</p>
|
||||
<p>Percentage of orders using STRIPE: {(stripe_orders / orders.length) * 100}%</p>
|
||||
<p>Percentage of STRIPE, stripe_status = SessionCreated: {stripe_sessioncreated} ({stripe_sessioncreated / stripe_orders * 100}%)</p>
|
||||
<p>Percentage of STRIPE, stripe_status = Failed: {stripe_failed} ({stripe_failed / stripe_orders * 100}%)</p>
|
||||
<p>Percentage of STRIPE, stripe_status = Paid: {stripe_paid} ({stripe_paid / stripe_orders * 100}%)</p>
|
||||
</PaperContent>
|
||||
</Paper>
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
import Tooltip, { Wrapper as TooltipWrapper } from "@smui/tooltip";
|
||||
|
||||
import "./style.scss";
|
||||
import {authToken} from "$lib/stores/AuthStore";
|
||||
|
||||
let loaded = false;
|
||||
let products = [];
|
||||
|
@ -26,7 +27,7 @@
|
|||
async function loadProducts() {
|
||||
loaded = false;
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/products`);
|
||||
let resp = await fetch(`${$serverUrl}/products`, {headers: [["Authorization", "Bearer " + $authToken]]});
|
||||
if (resp.ok) {
|
||||
let json = await resp.json();
|
||||
console.log(json);
|
||||
|
@ -86,7 +87,8 @@
|
|||
let resp = await fetch(`${$serverUrl}/products/${editingProductID}`, {
|
||||
method: 'PUT',
|
||||
headers: [
|
||||
['Content-Type', 'application/json']
|
||||
['Content-Type', 'application/json'],
|
||||
["Authorization", "Bearer " + $authToken]
|
||||
],
|
||||
body: JSON.stringify({
|
||||
name: editName,
|
||||
|
@ -126,7 +128,7 @@
|
|||
deletingProduct = false;
|
||||
loaded = false;
|
||||
try {
|
||||
let resp = await fetch(`${$serverUrl}/products/${id}`, {method: 'DELETE'});
|
||||
let resp = await fetch(`${$serverUrl}/products/${id}`, {method: 'DELETE', headers: [["Authorization", "Bearer " + $authToken]]});
|
||||
if (resp.ok) {
|
||||
loaded = true;
|
||||
await loadProducts();
|
||||
|
@ -177,7 +179,8 @@
|
|||
let resp = await fetch(`${$serverUrl}/products`, {
|
||||
method: 'POST',
|
||||
headers: [
|
||||
['Content-Type', 'application/json']
|
||||
['Content-Type', 'application/json'],
|
||||
["Authorization", "Bearer " + $authToken]
|
||||
],
|
||||
body: JSON.stringify({
|
||||
name: createName,
|
||||
|
|
Loading…
Reference in New Issue