feat: update shipping zone when re-issuing invoice
This commit is contained in:
parent
b5aed1224a
commit
02d9fcfbfd
5 changed files with 100 additions and 30 deletions
14
models.py
14
models.py
|
|
@ -45,6 +45,7 @@ class MerchantConfig(MerchantProfile):
|
||||||
active: bool = False
|
active: bool = False
|
||||||
restore_in_progress: Optional[bool] = False
|
restore_in_progress: Optional[bool] = False
|
||||||
|
|
||||||
|
|
||||||
class PartialMerchant(BaseModel):
|
class PartialMerchant(BaseModel):
|
||||||
private_key: str
|
private_key: str
|
||||||
public_key: str
|
public_key: str
|
||||||
|
|
@ -400,6 +401,11 @@ class OrderStatusUpdate(BaseModel):
|
||||||
shipped: Optional[bool]
|
shipped: Optional[bool]
|
||||||
|
|
||||||
|
|
||||||
|
class OrderReissue(BaseModel):
|
||||||
|
id: str
|
||||||
|
shipping_id: Optional[str] = None
|
||||||
|
|
||||||
|
|
||||||
class PaymentOption(BaseModel):
|
class PaymentOption(BaseModel):
|
||||||
type: str
|
type: str
|
||||||
link: str
|
link: str
|
||||||
|
|
@ -414,14 +420,15 @@ class PaymentRequest(BaseModel):
|
||||||
######################################## MESSAGE ########################################
|
######################################## MESSAGE ########################################
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class DirectMessageType(Enum):
|
class DirectMessageType(Enum):
|
||||||
"""Various types os direct messages."""
|
"""Various types os direct messages."""
|
||||||
|
|
||||||
PLAIN_TEXT = -1
|
PLAIN_TEXT = -1
|
||||||
CUSTOMER_ORDER = 0
|
CUSTOMER_ORDER = 0
|
||||||
PAYMENT_REQUEST = 1
|
PAYMENT_REQUEST = 1
|
||||||
ORDER_PAID_OR_SHIPPED = 2
|
ORDER_PAID_OR_SHIPPED = 2
|
||||||
|
|
||||||
|
|
||||||
class PartialDirectMessage(BaseModel):
|
class PartialDirectMessage(BaseModel):
|
||||||
event_id: Optional[str]
|
event_id: Optional[str]
|
||||||
event_created_at: Optional[int]
|
event_created_at: Optional[int]
|
||||||
|
|
@ -452,7 +459,6 @@ class DirectMessage(PartialDirectMessage):
|
||||||
return dm
|
return dm
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
######################################## CUSTOMERS ########################################
|
######################################## CUSTOMERS ########################################
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -471,5 +477,7 @@ class Customer(BaseModel):
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_row(cls, row: Row) -> "Customer":
|
def from_row(cls, row: Row) -> "Customer":
|
||||||
customer = cls(**dict(row))
|
customer = cls(**dict(row))
|
||||||
customer.profile = CustomerProfile(**json.loads(row["meta"])) if "meta" in row else None
|
customer.profile = (
|
||||||
|
CustomerProfile(**json.loads(row["meta"])) if "meta" in row else None
|
||||||
|
)
|
||||||
return customer
|
return customer
|
||||||
|
|
|
||||||
|
|
@ -275,7 +275,6 @@ async def process_nostr_message(msg: str):
|
||||||
if type.upper() == "EVENT":
|
if type.upper() == "EVENT":
|
||||||
subscription_id, event = rest
|
subscription_id, event = rest
|
||||||
event = NostrEvent(**event)
|
event = NostrEvent(**event)
|
||||||
print("kind: ", event.kind, ": ", msg)
|
|
||||||
if event.kind == 0:
|
if event.kind == 0:
|
||||||
await _handle_customer_profile_update(event)
|
await _handle_customer_profile_update(event)
|
||||||
elif event.kind == 4:
|
elif event.kind == 4:
|
||||||
|
|
|
||||||
|
|
@ -121,13 +121,6 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3 col-sm-1"></div>
|
<div class="col-3 col-sm-1"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
|
||||||
<div class="col-3 q-pr-lg">Address:</div>
|
|
||||||
<div class="col-6 col-sm-8 q-pr-lg">
|
|
||||||
<q-input filled dense readonly disabled v-model.trim="props.row.address" type="text"></q-input>
|
|
||||||
</div>
|
|
||||||
<div class="col-3 col-sm-1"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
<div class="col-3 q-pr-lg">Customer Public Key:</div>
|
<div class="col-3 q-pr-lg">Customer Public Key:</div>
|
||||||
|
|
@ -137,6 +130,14 @@
|
||||||
<div class="col-3 col-sm-1"></div>
|
<div class="col-3 col-sm-1"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div v-if="props.row.address" class="row items-center no-wrap q-mb-md">
|
||||||
|
<div class="col-3 q-pr-lg">Address:</div>
|
||||||
|
<div class="col-6 col-sm-8 q-pr-lg">
|
||||||
|
<q-input filled dense readonly disabled v-model.trim="props.row.address" type="text"></q-input>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 col-sm-1"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div v-if="props.row.contact.phone" class="row items-center no-wrap q-mb-md">
|
<div v-if="props.row.contact.phone" class="row items-center no-wrap q-mb-md">
|
||||||
<div class="col-3 q-pr-lg">Phone:</div>
|
<div class="col-3 q-pr-lg">Phone:</div>
|
||||||
<div class="col-6 col-sm-8 q-pr-lg">
|
<div class="col-6 col-sm-8 q-pr-lg">
|
||||||
|
|
@ -151,6 +152,14 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="col-3 col-sm-1"></div>
|
<div class="col-3 col-sm-1"></div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
|
<div class="col-3 q-pr-lg">Shipping Zone:</div>
|
||||||
|
<div class="col-6 col-sm-8 q-pr-lg">
|
||||||
|
<q-select :options="getStallZones(props.row.stall_id)" filled dense emit-value
|
||||||
|
v-model.trim="props.row.shipping_id" label="Shipping Zones"></q-select>
|
||||||
|
</div>
|
||||||
|
<div class="col-3 col-sm-1"></div>
|
||||||
|
</div>
|
||||||
<div class="row items-center no-wrap q-mb-md">
|
<div class="row items-center no-wrap q-mb-md">
|
||||||
<div class="col-3 q-pr-lg">Invoice ID:</div>
|
<div class="col-3 q-pr-lg">Invoice ID:</div>
|
||||||
<div class="col-6 col-sm-8 q-pr-lg">
|
<div class="col-6 col-sm-8 q-pr-lg">
|
||||||
|
|
@ -164,7 +173,8 @@
|
||||||
<div class="col-3 q-pr-lg"></div>
|
<div class="col-3 q-pr-lg"></div>
|
||||||
|
|
||||||
<div class="col-9">
|
<div class="col-9">
|
||||||
<q-btn @click="reissueOrderInvoice(props.row.id)" unelevated color="primary" type="submit" class="float-left" label="Reissue Invoice"></q-btn>
|
<q-btn @click="reissueOrderInvoice(props.row)" unelevated color="primary" type="submit"
|
||||||
|
class="float-left" label="Reissue Invoice"></q-btn>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</q-td>
|
</q-td>
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ async function orderList(path) {
|
||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
orders: [],
|
orders: [],
|
||||||
|
stalls: [],
|
||||||
selectedOrder: null,
|
selectedOrder: null,
|
||||||
shippingMessage: '',
|
shippingMessage: '',
|
||||||
showShipDialog: false,
|
showShipDialog: false,
|
||||||
|
|
@ -48,6 +49,7 @@ async function orderList(path) {
|
||||||
id: 'false'
|
id: 'false'
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
zoneOptions: [],
|
||||||
ordersTable: {
|
ordersTable: {
|
||||||
columns: [
|
columns: [
|
||||||
{
|
{
|
||||||
|
|
@ -205,22 +207,26 @@ async function orderList(path) {
|
||||||
this.search.restoring = false
|
this.search.restoring = false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
reissueOrderInvoice: async function (orderId) {
|
reissueOrderInvoice: async function (order) {
|
||||||
try {
|
try {
|
||||||
const { data } = await LNbits.api.request(
|
const { data } = await LNbits.api.request(
|
||||||
'PUT',
|
'PUT',
|
||||||
`/nostrmarket/api/v1/order/${orderId}/reissue`,
|
`/nostrmarket/api/v1/order/reissue`,
|
||||||
this.adminkey
|
this.adminkey,
|
||||||
|
{
|
||||||
|
id: order.id,
|
||||||
|
shipping_id: order.shipping_id
|
||||||
|
}
|
||||||
)
|
)
|
||||||
this.$q.notify({
|
this.$q.notify({
|
||||||
type: 'positive',
|
type: 'positive',
|
||||||
message: 'Order invoice reissued!'
|
message: 'Order invoice reissued!'
|
||||||
})
|
})
|
||||||
|
data.expanded = order.expanded
|
||||||
|
|
||||||
const i = this.orders.map(o => o.id).indexOf(orderId)
|
const i = this.orders.map(o => o.id).indexOf(order.id)
|
||||||
console.log('### order', i)
|
|
||||||
if (i !== -1) {
|
if (i !== -1) {
|
||||||
this.orders[i] = { ...this.orders[i], ...data}
|
this.orders[i] = { ...this.orders[i], ...data }
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
LNbits.utils.notifyApiError(error)
|
LNbits.utils.notifyApiError(error)
|
||||||
|
|
@ -265,6 +271,44 @@ async function orderList(path) {
|
||||||
order.isNew = false
|
order.isNew = false
|
||||||
this.orders = [order]
|
this.orders = [order]
|
||||||
},
|
},
|
||||||
|
getZones: async function () {
|
||||||
|
try {
|
||||||
|
const { data } = await LNbits.api.request(
|
||||||
|
'GET',
|
||||||
|
'/nostrmarket/api/v1/zone',
|
||||||
|
this.inkey
|
||||||
|
)
|
||||||
|
return data.map(z => ({
|
||||||
|
id: z.id,
|
||||||
|
value: z.id,
|
||||||
|
label: z.name
|
||||||
|
? `${z.name} (${z.countries.join(', ')})`
|
||||||
|
: z.countries.join(', ')
|
||||||
|
}))
|
||||||
|
} catch (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
getStalls: async function (pending = false) {
|
||||||
|
try {
|
||||||
|
const { data } = await LNbits.api.request(
|
||||||
|
'GET',
|
||||||
|
`/nostrmarket/api/v1/stall?pending=${pending}`,
|
||||||
|
this.inkey
|
||||||
|
)
|
||||||
|
return data.map(s => ({ ...s, expanded: false }))
|
||||||
|
} catch (error) {
|
||||||
|
LNbits.utils.notifyApiError(error)
|
||||||
|
}
|
||||||
|
return []
|
||||||
|
},
|
||||||
|
getStallZones: function (stallId) {
|
||||||
|
const stall = this.stalls.find(s => s.id === stallId)
|
||||||
|
if (!stall) return []
|
||||||
|
|
||||||
|
return this.zoneOptions.filter(z => stall.shipping_zones.find(s => s.id === z.id))
|
||||||
|
},
|
||||||
showShipOrderDialog: function (order) {
|
showShipOrderDialog: function (order) {
|
||||||
this.selectedOrder = order
|
this.selectedOrder = order
|
||||||
this.shippingMessage = order.shipped
|
this.shippingMessage = order.shipped
|
||||||
|
|
@ -312,6 +356,8 @@ async function orderList(path) {
|
||||||
await this.getOrders()
|
await this.getOrders()
|
||||||
}
|
}
|
||||||
await this.getCustomers()
|
await this.getCustomers()
|
||||||
|
this.zoneOptions = await this.getZones()
|
||||||
|
this.stalls = await this.getStalls()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
25
views_api.py
25
views_api.py
|
|
@ -66,6 +66,7 @@ from .models import (
|
||||||
DirectMessageType,
|
DirectMessageType,
|
||||||
Merchant,
|
Merchant,
|
||||||
Order,
|
Order,
|
||||||
|
OrderReissue,
|
||||||
OrderStatusUpdate,
|
OrderStatusUpdate,
|
||||||
PartialDirectMessage,
|
PartialDirectMessage,
|
||||||
PartialMerchant,
|
PartialMerchant,
|
||||||
|
|
@ -864,31 +865,37 @@ async def api_restore_orders(
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@nostrmarket_ext.put("/api/v1/order/{order_id}/reissue")
|
@nostrmarket_ext.put("/api/v1/order/reissue")
|
||||||
async def api_reissue_order_invoice(
|
async def api_reissue_order_invoice(
|
||||||
order_id: str,
|
reissue_data: OrderReissue,
|
||||||
wallet: WalletTypeInfo = Depends(require_admin_key),
|
wallet: WalletTypeInfo = Depends(require_admin_key),
|
||||||
) -> Order:
|
) -> Order:
|
||||||
try:
|
try:
|
||||||
merchant = await get_merchant_for_user(wallet.wallet.user)
|
merchant = await get_merchant_for_user(wallet.wallet.user)
|
||||||
assert merchant, "Merchant cannot be found"
|
assert merchant, "Merchant cannot be found"
|
||||||
|
|
||||||
data = await get_order(merchant.id, order_id)
|
data = await get_order(merchant.id, reissue_data.id)
|
||||||
assert data, "Order cannot be found"
|
assert data, "Order cannot be found"
|
||||||
|
|
||||||
|
if reissue_data.shipping_id:
|
||||||
|
data.shipping_id = reissue_data.shipping_id
|
||||||
|
|
||||||
order, invoice = await build_order_with_payment(
|
order, invoice = await build_order_with_payment(
|
||||||
merchant.id, merchant.public_key, PartialOrder(**data.dict())
|
merchant.id, merchant.public_key, PartialOrder(**data.dict())
|
||||||
)
|
)
|
||||||
|
|
||||||
|
order_update = {
|
||||||
|
"stall_id": order.stall_id,
|
||||||
|
"total": order.total,
|
||||||
|
"invoice_id": order.invoice_id,
|
||||||
|
"shipping_id": order.shipping_id,
|
||||||
|
"extra_data": json.dumps(order.extra.dict()),
|
||||||
|
}
|
||||||
|
|
||||||
await update_order(
|
await update_order(
|
||||||
merchant.id,
|
merchant.id,
|
||||||
order.id,
|
order.id,
|
||||||
**{
|
**order_update,
|
||||||
"stall_id": order.stall_id,
|
|
||||||
"total": order.total,
|
|
||||||
"invoice_id": order.invoice_id,
|
|
||||||
"extra_data": json.dumps(order.extra.dict()),
|
|
||||||
},
|
|
||||||
)
|
)
|
||||||
payment_req = PaymentRequest(
|
payment_req = PaymentRequest(
|
||||||
id=data.id, payment_options=[PaymentOption(type="ln", link=invoice)]
|
id=data.id, payment_options=[PaymentOption(type="ln", link=invoice)]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue