feat: allow invoice re-issue

This commit is contained in:
Vlad Stan 2023-07-04 16:40:33 +03:00
parent 4539e3a515
commit b5aed1224a
4 changed files with 110 additions and 10 deletions

View file

@ -407,7 +407,9 @@ async def _handle_incoming_dms(
merchant, new_dm, json_data merchant, new_dm, json_data
) )
if dm_reply: if dm_reply:
await _reply_to_structured_dm(merchant, event, reply_type.value, dm_reply) await reply_to_structured_dm(
merchant, event.pubkey, reply_type.value, dm_reply
)
async def _handle_outgoing_dms( async def _handle_outgoing_dms(
@ -474,15 +476,15 @@ async def _persist_dm(
return new_dm return new_dm
async def _reply_to_structured_dm( async def reply_to_structured_dm(
merchant: Merchant, event: NostrEvent, dm_type: int, dm_reply: str merchant: Merchant, customer_pubkey: str, dm_type: int, dm_reply: str
): ):
dm_event = merchant.build_dm_event(dm_reply, event.pubkey) dm_event = merchant.build_dm_event(dm_reply, customer_pubkey)
dm = PartialDirectMessage( dm = PartialDirectMessage(
event_id=dm_event.id, event_id=dm_event.id,
event_created_at=dm_event.created_at, event_created_at=dm_event.created_at,
message=dm_reply, message=dm_reply,
public_key=event.pubkey, public_key=customer_pubkey,
type=dm_type, type=dm_type,
) )
await create_direct_message(merchant.id, dm) await create_direct_message(merchant.id, dm)

View file

@ -156,7 +156,16 @@
<div class="col-6 col-sm-8 q-pr-lg"> <div class="col-6 col-sm-8 q-pr-lg">
<q-input filled dense readonly disabled v-model.trim="props.row.invoice_id" type="text"></q-input> <q-input filled dense readonly disabled v-model.trim="props.row.invoice_id" type="text"></q-input>
</div> </div>
<div class="col-3 col-sm-1"></div> <div class="col-3">
</div>
</div>
<div class="row items-center no-wrap q-mb-md">
<div class="col-3 q-pr-lg"></div>
<div class="col-9">
<q-btn @click="reissueOrderInvoice(props.row.id)" unelevated color="primary" type="submit" class="float-left" label="Reissue Invoice"></q-btn>
</div>
</div> </div>
</q-td> </q-td>
</q-tr> </q-tr>

View file

@ -205,6 +205,27 @@ async function orderList(path) {
this.search.restoring = false this.search.restoring = false
} }
}, },
reissueOrderInvoice: async function (orderId) {
try {
const { data } = await LNbits.api.request(
'PUT',
`/nostrmarket/api/v1/order/${orderId}/reissue`,
this.adminkey
)
this.$q.notify({
type: 'positive',
message: 'Order invoice reissued!'
})
const i = this.orders.map(o => o.id).indexOf(orderId)
console.log('### order', i)
if (i !== -1) {
this.orders[i] = { ...this.orders[i], ...data}
}
} catch (error) {
LNbits.utils.notifyApiError(error)
}
},
updateOrderShipped: async function () { updateOrderShipped: async function () {
this.selectedOrder.shipped = !this.selectedOrder.shipped this.selectedOrder.shipped = !this.selectedOrder.shipped
try { try {

View file

@ -53,6 +53,7 @@ from .crud import (
touch_merchant, touch_merchant,
update_customer_no_unread_messages, update_customer_no_unread_messages,
update_merchant, update_merchant,
update_order,
update_order_shipped_status, update_order_shipped_status,
update_product, update_product,
update_stall, update_stall,
@ -68,14 +69,19 @@ from .models import (
OrderStatusUpdate, OrderStatusUpdate,
PartialDirectMessage, PartialDirectMessage,
PartialMerchant, PartialMerchant,
PartialOrder,
PartialProduct, PartialProduct,
PartialStall, PartialStall,
PartialZone, PartialZone,
PaymentOption,
PaymentRequest,
Product, Product,
Stall, Stall,
Zone, Zone,
) )
from .services import ( from .services import (
reply_to_structured_dm,
build_order_with_payment,
create_or_update_order_from_dm, create_or_update_order_from_dm,
sign_and_send_to_nostr, sign_and_send_to_nostr,
update_merchant_to_nostr, update_merchant_to_nostr,
@ -102,7 +108,7 @@ async def api_create_merchant(
await create_zone( await create_zone(
merchant.id, merchant.id,
PartialZone( PartialZone(
id=f"online-{merchant.id}", id=f"online-{merchant.public_key}",
name="Online", name="Online",
currency="sat", currency="sat",
cost=0, cost=0,
@ -137,7 +143,7 @@ async def api_get_merchant(
merchant = await get_merchant_for_user(wallet.wallet.user) merchant = await get_merchant_for_user(wallet.wallet.user)
if not merchant: if not merchant:
return return
merchant = await touch_merchant(wallet.wallet.user, merchant.id) merchant = await touch_merchant(wallet.wallet.user, merchant.id)
last_dm_time = await get_last_direct_messages_time(merchant.id) last_dm_time = await get_last_direct_messages_time(merchant.id)
@ -210,6 +216,7 @@ async def api_republish_merchant(
detail="Cannot get merchant", detail="Cannot get merchant",
) )
@nostrmarket_ext.put("/api/v1/merchant/{merchant_id}/toggle") @nostrmarket_ext.put("/api/v1/merchant/{merchant_id}/toggle")
async def api_republish_merchant( async def api_republish_merchant(
merchant_id: str, merchant_id: str,
@ -237,7 +244,6 @@ async def api_republish_merchant(
) )
@nostrmarket_ext.delete("/api/v1/merchant/{merchant_id}/nostr") @nostrmarket_ext.delete("/api/v1/merchant/{merchant_id}/nostr")
async def api_delete_merchant( async def api_delete_merchant(
merchant_id: str, merchant_id: str,
@ -802,7 +808,13 @@ async def api_update_order_status(
await nostr_client.publish_nostr_event(dm_event) await nostr_client.publish_nostr_event(dm_event)
await websocketUpdater( await websocketUpdater(
merchant.id, merchant.id,
json.dumps({ "type": f"dm:{dm.type}", "customerPubkey": order.public_key, "dm": dm.dict() }), json.dumps(
{
"type": f"dm:{dm.type}",
"customerPubkey": order.public_key,
"dm": dm.dict(),
}
),
) )
return order return order
@ -852,6 +864,62 @@ async def api_restore_orders(
) )
@nostrmarket_ext.put("/api/v1/order/{order_id}/reissue")
async def api_reissue_order_invoice(
order_id: str,
wallet: WalletTypeInfo = Depends(require_admin_key),
) -> Order:
try:
merchant = await get_merchant_for_user(wallet.wallet.user)
assert merchant, "Merchant cannot be found"
data = await get_order(merchant.id, order_id)
assert data, "Order cannot be found"
order, invoice = await build_order_with_payment(
merchant.id, merchant.public_key, PartialOrder(**data.dict())
)
await update_order(
merchant.id,
order.id,
**{
"stall_id": order.stall_id,
"total": order.total,
"invoice_id": order.invoice_id,
"extra_data": json.dumps(order.extra.dict()),
},
)
payment_req = PaymentRequest(
id=data.id, payment_options=[PaymentOption(type="ln", link=invoice)]
)
response = {
"type": DirectMessageType.PAYMENT_REQUEST.value,
**payment_req.dict(),
}
dm_reply = json.dumps(response, separators=(",", ":"), ensure_ascii=False)
await reply_to_structured_dm(
merchant,
order.public_key,
DirectMessageType.PAYMENT_REQUEST.value,
dm_reply,
)
return order
except AssertionError as ex:
raise HTTPException(
status_code=HTTPStatus.BAD_REQUEST,
detail=str(ex),
)
except Exception as ex:
logger.warning(ex)
raise HTTPException(
status_code=HTTPStatus.INTERNAL_SERVER_ERROR,
detail="Cannot restore orders",
)
######################################## DIRECT MESSAGES ######################################## ######################################## DIRECT MESSAGES ########################################