1use jni::JNIEnv;
6use jni::objects::{JClass, JObject, JString, JValue};
7use jni::sys::{jdouble, jint, jlong};
8use rust_decimal::Decimal;
9use stateset_core::{OrderStatus, ReturnReason};
10use stateset_embedded::{
11 AddCartItem, AnalyticsQuery, Commerce as RustCommerce, CreateCart, CreateCustomer,
12 CreateInventoryItem, CreateOrder, CreatePayment, CreateProduct, CreateProductVariant,
13 CreateReturn, CreateReturnItem, CustomerFilter, OrderFilter, PaymentMethodType, ProductFilter,
14 TimePeriod,
15};
16use std::sync::{Arc, Mutex};
17
18type CommerceHandle = Arc<Mutex<RustCommerce>>;
24
25fn create_handle(commerce: RustCommerce) -> jlong {
26 let handle: CommerceHandle = Arc::new(Mutex::new(commerce));
27 Arc::into_raw(handle) as jlong
28}
29
30fn get_handle(ptr: jlong) -> Option<CommerceHandle> {
31 if ptr == 0 {
32 return None;
33 }
34 let raw = ptr as *const Mutex<RustCommerce>;
35 unsafe {
36 Arc::increment_strong_count(raw);
37 Some(Arc::from_raw(raw))
38 }
39}
40
41fn use_handle<F, R>(ptr: jlong, f: F) -> Result<R, String>
42where
43 F: FnOnce(&RustCommerce) -> Result<R, String>,
44{
45 let handle = get_handle(ptr).ok_or_else(|| "Null handle".to_string())?;
46 let guard = handle.lock().map_err(|e| format!("Lock failed: {}", e))?;
47 f(&guard)
48}
49
50fn get_string(env: &mut JNIEnv<'_>, s: &JString<'_>) -> String {
55 env.get_string(s).map(|s| s.into()).unwrap_or_default()
56}
57
58fn throw_exception(env: &mut JNIEnv<'_>, msg: &str) {
59 let _ = env.throw_new("com/stateset/embedded/StateSetException", msg);
60}
61
62fn jni_or_throw<'a, T>(
63 env: &mut JNIEnv<'a>,
64 result: jni::errors::Result<T>,
65 context: &str,
66) -> Option<T> {
67 match result {
68 Ok(value) => Some(value),
69 Err(err) => {
70 throw_exception(env, &format!("{}: {}", context, err));
71 None
72 }
73 }
74}
75
76fn to_f64_or_nan<T>(value: T) -> f64
77where
78 T: TryInto<f64>,
79 <T as TryInto<f64>>::Error: std::fmt::Display,
80{
81 match value.try_into() {
82 Ok(converted) => converted,
83 Err(err) => {
84 eprintln!("stateset-embedded: failed to convert to f64: {}", err);
85 f64::NAN
86 }
87 }
88}
89
90fn create_customer_object<'a>(
91 env: &mut JNIEnv<'a>,
92 customer: &stateset_core::Customer,
93) -> JObject<'a> {
94 let class_result = env.find_class("com/stateset/embedded/Customer");
95 let class = match jni_or_throw(env, class_result, "Customer class not found") {
96 Some(value) => value,
97 None => return JObject::null(),
98 };
99 let id_result = env.new_string(customer.id.to_string());
100 let id = match jni_or_throw(env, id_result, "Failed to create customer id") {
101 Some(value) => value,
102 None => return JObject::null(),
103 };
104 let email_result = env.new_string(&customer.email);
105 let email = match jni_or_throw(env, email_result, "Failed to create customer email") {
106 Some(value) => value,
107 None => return JObject::null(),
108 };
109 let first_name_result = env.new_string(&customer.first_name);
110 let first_name =
111 match jni_or_throw(env, first_name_result, "Failed to create customer first name") {
112 Some(value) => value,
113 None => return JObject::null(),
114 };
115 let last_name_result = env.new_string(&customer.last_name);
116 let last_name = match jni_or_throw(env, last_name_result, "Failed to create customer last name")
117 {
118 Some(value) => value,
119 None => return JObject::null(),
120 };
121 let phone_result = env.new_string(customer.phone.as_deref().unwrap_or(""));
122 let phone = match jni_or_throw(env, phone_result, "Failed to create customer phone") {
123 Some(value) => value,
124 None => return JObject::null(),
125 };
126 let created_at_result = env.new_string(customer.created_at.to_rfc3339());
127 let created_at =
128 match jni_or_throw(env, created_at_result, "Failed to create customer created_at") {
129 Some(value) => value,
130 None => return JObject::null(),
131 };
132
133 let obj_result = env.new_object(
134 class,
135 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V",
136 &[
137 JValue::Object(&id),
138 JValue::Object(&email),
139 JValue::Object(&first_name),
140 JValue::Object(&last_name),
141 JValue::Object(&phone),
142 JValue::Object(&created_at),
143 ],
144 );
145 match jni_or_throw(env, obj_result, "Failed to create customer object") {
146 Some(obj) => obj,
147 None => JObject::null(),
148 }
149}
150
151fn create_product_object<'a>(
152 env: &mut JNIEnv<'a>,
153 product: &stateset_core::Product,
154) -> JObject<'a> {
155 let class_result = env.find_class("com/stateset/embedded/Product");
156 let class = match jni_or_throw(env, class_result, "Product class not found") {
157 Some(value) => value,
158 None => return JObject::null(),
159 };
160 let id_result = env.new_string(product.id.to_string());
161 let id = match jni_or_throw(env, id_result, "Failed to create product id") {
162 Some(value) => value,
163 None => return JObject::null(),
164 };
165 let sku_result = env.new_string(&product.slug);
167 let sku = match jni_or_throw(env, sku_result, "Failed to create product sku") {
168 Some(value) => value,
169 None => return JObject::null(),
170 };
171 let name_result = env.new_string(&product.name);
172 let name = match jni_or_throw(env, name_result, "Failed to create product name") {
173 Some(value) => value,
174 None => return JObject::null(),
175 };
176 let base_price: f64 = 0.0;
178
179 let obj_result = env.new_object(
180 class,
181 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;D)V",
182 &[
183 JValue::Object(&id),
184 JValue::Object(&sku),
185 JValue::Object(&name),
186 JValue::Double(base_price),
187 ],
188 );
189 match jni_or_throw(env, obj_result, "Failed to create product object") {
190 Some(obj) => obj,
191 None => JObject::null(),
192 }
193}
194
195fn create_order_object<'a>(env: &mut JNIEnv<'a>, order: &stateset_core::Order) -> JObject<'a> {
196 let class_result = env.find_class("com/stateset/embedded/Order");
197 let class = match jni_or_throw(env, class_result, "Order class not found") {
198 Some(value) => value,
199 None => return JObject::null(),
200 };
201 let id_result = env.new_string(order.id.to_string());
202 let id = match jni_or_throw(env, id_result, "Failed to create order id") {
203 Some(value) => value,
204 None => return JObject::null(),
205 };
206 let order_number_result = env.new_string(&order.order_number);
207 let order_number = match jni_or_throw(env, order_number_result, "Failed to create order number")
208 {
209 Some(value) => value,
210 None => return JObject::null(),
211 };
212 let customer_id_result = env.new_string(order.customer_id.to_string());
213 let customer_id =
214 match jni_or_throw(env, customer_id_result, "Failed to create order customer id") {
215 Some(value) => value,
216 None => return JObject::null(),
217 };
218 let status_result = env.new_string(format!("{:?}", order.status));
219 let status = match jni_or_throw(env, status_result, "Failed to create order status") {
220 Some(value) => value,
221 None => return JObject::null(),
222 };
223 let total: f64 = to_f64_or_nan(order.total_amount);
224 let currency_result = env.new_string(&order.currency);
225 let currency = match jni_or_throw(env, currency_result, "Failed to create order currency") {
226 Some(value) => value,
227 None => return JObject::null(),
228 };
229 let created_at_result = env.new_string(order.created_at.to_rfc3339());
230 let created_at = match jni_or_throw(env, created_at_result, "Failed to create order created_at")
231 {
232 Some(value) => value,
233 None => return JObject::null(),
234 };
235
236 let obj_result = env.new_object(
237 class,
238 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;Ljava/lang/String;)V",
239 &[
240 JValue::Object(&id),
241 JValue::Object(&order_number),
242 JValue::Object(&customer_id),
243 JValue::Object(&status),
244 JValue::Double(total),
245 JValue::Object(¤cy),
246 JValue::Object(&created_at),
247 ],
248 );
249 match jni_or_throw(env, obj_result, "Failed to create order object") {
250 Some(obj) => obj,
251 None => JObject::null(),
252 }
253}
254
255fn create_inventory_item_object<'a>(
256 env: &mut JNIEnv<'a>,
257 item: &stateset_core::InventoryItem,
258) -> JObject<'a> {
259 let class_result = env.find_class("com/stateset/embedded/InventoryItem");
260 let class = match jni_or_throw(env, class_result, "InventoryItem class not found") {
261 Some(value) => value,
262 None => return JObject::null(),
263 };
264 let id_result = env.new_string(item.id.to_string());
265 let id = match jni_or_throw(env, id_result, "Failed to create inventory item id") {
266 Some(value) => value,
267 None => return JObject::null(),
268 };
269 let sku_result = env.new_string(&item.sku);
270 let sku = match jni_or_throw(env, sku_result, "Failed to create inventory item sku") {
271 Some(value) => value,
272 None => return JObject::null(),
273 };
274 let name_result = env.new_string(&item.name);
275 let name = match jni_or_throw(env, name_result, "Failed to create inventory item name") {
276 Some(value) => value,
277 None => return JObject::null(),
278 };
279 let available: f64 = 0.0;
282 let reserved: f64 = 0.0;
283
284 let obj_result = env.new_object(
285 class,
286 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DD)V",
287 &[
288 JValue::Object(&id),
289 JValue::Object(&sku),
290 JValue::Object(&name),
291 JValue::Double(available),
292 JValue::Double(reserved),
293 ],
294 );
295 match jni_or_throw(env, obj_result, "Failed to create inventory item object") {
296 Some(obj) => obj,
297 None => JObject::null(),
298 }
299}
300
301fn create_cart_object<'a>(env: &mut JNIEnv<'a>, cart: &stateset_core::Cart) -> JObject<'a> {
302 let class_result = env.find_class("com/stateset/embedded/Cart");
303 let class = match jni_or_throw(env, class_result, "Cart class not found") {
304 Some(value) => value,
305 None => return JObject::null(),
306 };
307 let id_result = env.new_string(cart.id.to_string());
308 let id = match jni_or_throw(env, id_result, "Failed to create cart id") {
309 Some(value) => value,
310 None => return JObject::null(),
311 };
312 let customer_id_result =
313 env.new_string(cart.customer_id.map(|id| id.to_string()).unwrap_or_default());
314 let customer_id =
315 match jni_or_throw(env, customer_id_result, "Failed to create cart customer id") {
316 Some(value) => value,
317 None => return JObject::null(),
318 };
319 let status_result = env.new_string(format!("{:?}", cart.status));
320 let status = match jni_or_throw(env, status_result, "Failed to create cart status") {
321 Some(value) => value,
322 None => return JObject::null(),
323 };
324 let total: f64 = to_f64_or_nan(cart.grand_total);
325 let currency_result = env.new_string(&cart.currency);
326 let currency = match jni_or_throw(env, currency_result, "Failed to create cart currency") {
327 Some(value) => value,
328 None => return JObject::null(),
329 };
330
331 let obj_result = env.new_object(
332 class,
333 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;DLjava/lang/String;)V",
334 &[
335 JValue::Object(&id),
336 JValue::Object(&customer_id),
337 JValue::Object(&status),
338 JValue::Double(total),
339 JValue::Object(¤cy),
340 ],
341 );
342 match jni_or_throw(env, obj_result, "Failed to create cart object") {
343 Some(obj) => obj,
344 None => JObject::null(),
345 }
346}
347
348fn create_sales_summary_object<'a>(
349 env: &mut JNIEnv<'a>,
350 summary: &stateset_core::SalesSummary,
351) -> JObject<'a> {
352 let class_result = env.find_class("com/stateset/embedded/SalesSummary");
353 let class = match jni_or_throw(env, class_result, "SalesSummary class not found") {
354 Some(value) => value,
355 None => return JObject::null(),
356 };
357 let total_revenue: f64 = to_f64_or_nan(summary.total_revenue);
358 let total_orders = summary.order_count as jint;
359 let aov: f64 = to_f64_or_nan(summary.average_order_value);
360
361 let obj_result = env.new_object(
362 class,
363 "(DID)V",
364 &[JValue::Double(total_revenue), JValue::Int(total_orders), JValue::Double(aov)],
365 );
366 match jni_or_throw(env, obj_result, "Failed to create sales summary object") {
367 Some(obj) => obj,
368 None => JObject::null(),
369 }
370}
371
372fn create_return_object<'a>(env: &mut JNIEnv<'a>, ret: &stateset_core::Return) -> JObject<'a> {
373 let class_result = env.find_class("com/stateset/embedded/ReturnRequest");
374 let class = match jni_or_throw(env, class_result, "ReturnRequest class not found") {
375 Some(value) => value,
376 None => return JObject::null(),
377 };
378 let id_result = env.new_string(ret.id.to_string());
379 let id = match jni_or_throw(env, id_result, "Failed to create return id") {
380 Some(value) => value,
381 None => return JObject::null(),
382 };
383 let order_id_result = env.new_string(ret.order_id.to_string());
384 let order_id = match jni_or_throw(env, order_id_result, "Failed to create return order id") {
385 Some(value) => value,
386 None => return JObject::null(),
387 };
388 let reason_result = env.new_string(format!("{:?}", ret.reason));
389 let reason = match jni_or_throw(env, reason_result, "Failed to create return reason") {
390 Some(value) => value,
391 None => return JObject::null(),
392 };
393 let status_result = env.new_string(format!("{:?}", ret.status));
394 let status = match jni_or_throw(env, status_result, "Failed to create return status") {
395 Some(value) => value,
396 None => return JObject::null(),
397 };
398 let refund_amount: f64 = ret.refund_amount.map(to_f64_or_nan).unwrap_or(0.0);
399
400 let obj_result = env.new_object(
401 class,
402 "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;D)V",
403 &[
404 JValue::Object(&id),
405 JValue::Object(&order_id),
406 JValue::Object(&reason),
407 JValue::Object(&status),
408 JValue::Double(refund_amount),
409 ],
410 );
411 match jni_or_throw(env, obj_result, "Failed to create return object") {
412 Some(obj) => obj,
413 None => JObject::null(),
414 }
415}
416
417#[unsafe(no_mangle)]
422pub extern "system" fn Java_com_stateset_embedded_Commerce_nativeCreate<'local>(
423 mut env: JNIEnv<'local>,
424 _class: JClass<'local>,
425 db_path: JString<'local>,
426) -> jlong {
427 let path = get_string(&mut env, &db_path);
428
429 match RustCommerce::new(&path) {
430 Ok(commerce) => create_handle(commerce),
431 Err(e) => {
432 throw_exception(&mut env, &format!("Failed to create commerce: {}", e));
433 0
434 }
435 }
436}
437
438#[unsafe(no_mangle)]
439pub extern "system" fn Java_com_stateset_embedded_Commerce_nativeDestroy<'local>(
440 _env: JNIEnv<'local>,
441 _class: JClass<'local>,
442 ptr: jlong,
443) {
444 if ptr != 0 {
445 let _ = unsafe { Arc::from_raw(ptr as *const Mutex<RustCommerce>) };
447 }
448}
449
450#[unsafe(no_mangle)]
455pub extern "system" fn Java_com_stateset_embedded_Customers_nativeCreate<'local>(
456 mut env: JNIEnv<'local>,
457 _class: JClass<'local>,
458 ptr: jlong,
459 email: JString<'local>,
460 first_name: JString<'local>,
461 last_name: JString<'local>,
462) -> JObject<'local> {
463 let email_str = get_string(&mut env, &email);
464 let first_name_str = get_string(&mut env, &first_name);
465 let last_name_str = get_string(&mut env, &last_name);
466
467 let result = use_handle(ptr, |commerce| {
468 commerce
469 .customers()
470 .create(CreateCustomer {
471 email: email_str,
472 first_name: first_name_str,
473 last_name: last_name_str,
474 ..Default::default()
475 })
476 .map_err(|e| e.to_string())
477 });
478
479 match result {
480 Ok(customer) => create_customer_object(&mut env, &customer),
481 Err(e) => {
482 throw_exception(&mut env, &e);
483 JObject::null()
484 }
485 }
486}
487
488#[unsafe(no_mangle)]
489pub extern "system" fn Java_com_stateset_embedded_Customers_nativeGet<'local>(
490 mut env: JNIEnv<'local>,
491 _class: JClass<'local>,
492 ptr: jlong,
493 id: JString<'local>,
494) -> JObject<'local> {
495 let id_str = get_string(&mut env, &id);
496 let uuid = match uuid::Uuid::parse_str(&id_str) {
497 Ok(u) => u,
498 Err(_) => {
499 throw_exception(&mut env, "Invalid UUID");
500 return JObject::null();
501 }
502 };
503
504 let result = use_handle(ptr, |commerce| {
505 commerce.customers().get(uuid.into()).map_err(|e| e.to_string())
506 });
507
508 match result {
509 Ok(Some(customer)) => create_customer_object(&mut env, &customer),
510 Ok(None) => JObject::null(),
511 Err(e) => {
512 throw_exception(&mut env, &e);
513 JObject::null()
514 }
515 }
516}
517
518#[unsafe(no_mangle)]
519pub extern "system" fn Java_com_stateset_embedded_Customers_nativeList<'local>(
520 mut env: JNIEnv<'local>,
521 _class: JClass<'local>,
522 ptr: jlong,
523) -> JObject<'local> {
524 let result = use_handle(ptr, |commerce| {
525 commerce.customers().list(CustomerFilter::default()).map_err(|e| e.to_string())
526 });
527
528 match result {
529 Ok(customers) => {
530 let find_class_result = env.find_class("java/util/ArrayList");
531 let list_class =
532 match jni_or_throw(&mut env, find_class_result, "ArrayList class not found") {
533 Some(value) => value,
534 None => return JObject::null(),
535 };
536 let new_object_result = env.new_object(list_class, "()V", &[]);
537 let list = match jni_or_throw(&mut env, new_object_result, "Failed to create ArrayList")
538 {
539 Some(value) => value,
540 None => return JObject::null(),
541 };
542
543 for customer in &customers {
544 let obj = create_customer_object(&mut env, customer);
545 let add_result =
546 env.call_method(&list, "add", "(Ljava/lang/Object;)Z", &[JValue::Object(&obj)]);
547 if jni_or_throw(&mut env, add_result, "Failed to add customer to list").is_none() {
548 return JObject::null();
549 }
550 }
551
552 list
553 }
554 Err(e) => {
555 throw_exception(&mut env, &e);
556 JObject::null()
557 }
558 }
559}
560
561#[unsafe(no_mangle)]
566pub extern "system" fn Java_com_stateset_embedded_Products_nativeCreate<'local>(
567 mut env: JNIEnv<'local>,
568 _class: JClass<'local>,
569 ptr: jlong,
570 sku: JString<'local>,
571 name: JString<'local>,
572 base_price: jdouble,
573) -> JObject<'local> {
574 let sku_str = get_string(&mut env, &sku);
575 let name_str = get_string(&mut env, &name);
576 let price = Decimal::try_from(base_price).unwrap_or_default();
577
578 let result = use_handle(ptr, |commerce| {
579 commerce
581 .products()
582 .create(CreateProduct {
583 name: name_str,
584 variants: Some(vec![CreateProductVariant {
585 sku: sku_str,
586 price,
587 is_default: Some(true),
588 ..Default::default()
589 }]),
590 ..Default::default()
591 })
592 .map_err(|e| e.to_string())
593 });
594
595 match result {
596 Ok(product) => create_product_object(&mut env, &product),
597 Err(e) => {
598 throw_exception(&mut env, &e);
599 JObject::null()
600 }
601 }
602}
603
604#[unsafe(no_mangle)]
605pub extern "system" fn Java_com_stateset_embedded_Products_nativeGet<'local>(
606 mut env: JNIEnv<'local>,
607 _class: JClass<'local>,
608 ptr: jlong,
609 sku: JString<'local>,
610) -> JObject<'local> {
611 let sku_str = get_string(&mut env, &sku);
612
613 let result = use_handle(ptr, |commerce| {
615 if let Some(variant) =
616 commerce.products().get_variant_by_sku(&sku_str).map_err(|e| e.to_string())?
617 {
618 commerce.products().get(variant.product_id).map_err(|e| e.to_string())
619 } else {
620 Ok(None)
621 }
622 });
623
624 match result {
625 Ok(Some(product)) => create_product_object(&mut env, &product),
626 Ok(None) => JObject::null(),
627 Err(e) => {
628 throw_exception(&mut env, &e);
629 JObject::null()
630 }
631 }
632}
633
634#[unsafe(no_mangle)]
635pub extern "system" fn Java_com_stateset_embedded_Products_nativeList<'local>(
636 mut env: JNIEnv<'local>,
637 _class: JClass<'local>,
638 ptr: jlong,
639) -> JObject<'local> {
640 let result = use_handle(ptr, |commerce| {
641 commerce.products().list(ProductFilter::default()).map_err(|e| e.to_string())
642 });
643
644 match result {
645 Ok(products) => {
646 let find_class_result = env.find_class("java/util/ArrayList");
647 let list_class =
648 match jni_or_throw(&mut env, find_class_result, "ArrayList class not found") {
649 Some(value) => value,
650 None => return JObject::null(),
651 };
652 let new_object_result = env.new_object(list_class, "()V", &[]);
653 let list = match jni_or_throw(&mut env, new_object_result, "Failed to create ArrayList")
654 {
655 Some(value) => value,
656 None => return JObject::null(),
657 };
658
659 for product in &products {
660 let obj = create_product_object(&mut env, product);
661 let add_result =
662 env.call_method(&list, "add", "(Ljava/lang/Object;)Z", &[JValue::Object(&obj)]);
663 if jni_or_throw(&mut env, add_result, "Failed to add product to list").is_none() {
664 return JObject::null();
665 }
666 }
667
668 list
669 }
670 Err(e) => {
671 throw_exception(&mut env, &e);
672 JObject::null()
673 }
674 }
675}
676
677#[unsafe(no_mangle)]
682pub extern "system" fn Java_com_stateset_embedded_Inventory_nativeCreateItem<'local>(
683 mut env: JNIEnv<'local>,
684 _class: JClass<'local>,
685 ptr: jlong,
686 sku: JString<'local>,
687 name: JString<'local>,
688 initial_quantity: jdouble,
689) -> JObject<'local> {
690 let sku_str = get_string(&mut env, &sku);
691 let name_str = get_string(&mut env, &name);
692 let qty = Decimal::try_from(initial_quantity).ok();
693
694 let result = use_handle(ptr, |commerce| {
695 commerce
696 .inventory()
697 .create_item(CreateInventoryItem {
698 sku: sku_str,
699 name: name_str,
700 initial_quantity: qty,
701 ..Default::default()
702 })
703 .map_err(|e| e.to_string())
704 });
705
706 match result {
707 Ok(item) => create_inventory_item_object(&mut env, &item),
708 Err(e) => {
709 throw_exception(&mut env, &e);
710 JObject::null()
711 }
712 }
713}
714
715#[unsafe(no_mangle)]
716pub extern "system" fn Java_com_stateset_embedded_Inventory_nativeAdjust<'local>(
717 mut env: JNIEnv<'local>,
718 _class: JClass<'local>,
719 ptr: jlong,
720 sku: JString<'local>,
721 quantity: jdouble,
722 reason: JString<'local>,
723) -> JObject<'local> {
724 let sku_str = get_string(&mut env, &sku);
725 let reason_str = get_string(&mut env, &reason);
726 let qty = Decimal::try_from(quantity).unwrap_or_default();
727
728 let result = use_handle(ptr, |commerce| {
729 commerce.inventory().adjust(&sku_str, qty, &reason_str).map_err(|e| e.to_string())?;
730 commerce
732 .inventory()
733 .get_item_by_sku(&sku_str)
734 .map_err(|e| e.to_string())?
735 .ok_or_else(|| "Item not found".to_string())
736 });
737
738 match result {
739 Ok(item) => create_inventory_item_object(&mut env, &item),
740 Err(e) => {
741 throw_exception(&mut env, &e);
742 JObject::null()
743 }
744 }
745}
746
747#[unsafe(no_mangle)]
748pub extern "system" fn Java_com_stateset_embedded_Inventory_nativeGet<'local>(
749 mut env: JNIEnv<'local>,
750 _class: JClass<'local>,
751 ptr: jlong,
752 sku: JString<'local>,
753) -> JObject<'local> {
754 let sku_str = get_string(&mut env, &sku);
755
756 let result = use_handle(ptr, |commerce| {
757 commerce.inventory().get_item_by_sku(&sku_str).map_err(|e| e.to_string())
758 });
759
760 match result {
761 Ok(Some(item)) => create_inventory_item_object(&mut env, &item),
762 Ok(None) => JObject::null(),
763 Err(e) => {
764 throw_exception(&mut env, &e);
765 JObject::null()
766 }
767 }
768}
769
770#[unsafe(no_mangle)]
771pub extern "system" fn Java_com_stateset_embedded_Inventory_nativeReserve<'local>(
772 mut env: JNIEnv<'local>,
773 _class: JClass<'local>,
774 ptr: jlong,
775 sku: JString<'local>,
776 quantity: jdouble,
777) {
778 let sku_str = get_string(&mut env, &sku);
779 let qty = Decimal::try_from(quantity).unwrap_or_default();
780
781 let result = use_handle(ptr, |commerce| {
782 commerce
783 .inventory()
784 .reserve(&sku_str, qty, "java", "reservation", None)
785 .map_err(|e| e.to_string())
786 });
787
788 if let Err(e) = result {
789 throw_exception(&mut env, &e);
790 }
791}
792
793#[unsafe(no_mangle)]
794pub extern "system" fn Java_com_stateset_embedded_Inventory_nativeRelease<'local>(
795 mut env: JNIEnv<'local>,
796 _class: JClass<'local>,
797 _ptr: jlong,
798 sku: JString<'local>,
799 _quantity: jdouble,
800) {
801 let _sku_str = get_string(&mut env, &sku);
802 throw_exception(&mut env, "Release requires reservation ID, not SKU");
805}
806
807#[unsafe(no_mangle)]
812pub extern "system" fn Java_com_stateset_embedded_Orders_nativeCreate<'local>(
813 mut env: JNIEnv<'local>,
814 _class: JClass<'local>,
815 ptr: jlong,
816 customer_id: JString<'local>,
817 currency: JString<'local>,
818) -> JObject<'local> {
819 let customer_id_str = get_string(&mut env, &customer_id);
820 let currency_str = get_string(&mut env, ¤cy);
821
822 let uuid = match uuid::Uuid::parse_str(&customer_id_str) {
823 Ok(u) => u,
824 Err(_) => {
825 throw_exception(&mut env, "Invalid customer UUID");
826 return JObject::null();
827 }
828 };
829
830 let result = use_handle(ptr, |commerce| {
831 commerce
832 .orders()
833 .create(CreateOrder {
834 customer_id: uuid.into(),
835 currency: Some(if currency_str.is_empty() {
836 "USD".to_string()
837 } else {
838 currency_str
839 }),
840 items: vec![],
841 ..Default::default()
842 })
843 .map_err(|e| e.to_string())
844 });
845
846 match result {
847 Ok(order) => create_order_object(&mut env, &order),
848 Err(e) => {
849 throw_exception(&mut env, &e);
850 JObject::null()
851 }
852 }
853}
854
855#[unsafe(no_mangle)]
856pub extern "system" fn Java_com_stateset_embedded_Orders_nativeGet<'local>(
857 mut env: JNIEnv<'local>,
858 _class: JClass<'local>,
859 ptr: jlong,
860 id: JString<'local>,
861) -> JObject<'local> {
862 let id_str = get_string(&mut env, &id);
863 let uuid = match uuid::Uuid::parse_str(&id_str) {
864 Ok(u) => u,
865 Err(_) => {
866 throw_exception(&mut env, "Invalid UUID");
867 return JObject::null();
868 }
869 };
870
871 let result =
872 use_handle(ptr, |commerce| commerce.orders().get(uuid.into()).map_err(|e| e.to_string()));
873
874 match result {
875 Ok(Some(order)) => create_order_object(&mut env, &order),
876 Ok(None) => JObject::null(),
877 Err(e) => {
878 throw_exception(&mut env, &e);
879 JObject::null()
880 }
881 }
882}
883
884#[unsafe(no_mangle)]
885pub extern "system" fn Java_com_stateset_embedded_Orders_nativeList<'local>(
886 mut env: JNIEnv<'local>,
887 _class: JClass<'local>,
888 ptr: jlong,
889) -> JObject<'local> {
890 let result = use_handle(ptr, |commerce| {
891 commerce.orders().list(OrderFilter::default()).map_err(|e| e.to_string())
892 });
893
894 match result {
895 Ok(orders) => {
896 let find_class_result = env.find_class("java/util/ArrayList");
897 let list_class =
898 match jni_or_throw(&mut env, find_class_result, "ArrayList class not found") {
899 Some(value) => value,
900 None => return JObject::null(),
901 };
902 let new_object_result = env.new_object(list_class, "()V", &[]);
903 let list = match jni_or_throw(&mut env, new_object_result, "Failed to create ArrayList")
904 {
905 Some(value) => value,
906 None => return JObject::null(),
907 };
908
909 for order in &orders {
910 let obj = create_order_object(&mut env, order);
911 let add_result =
912 env.call_method(&list, "add", "(Ljava/lang/Object;)Z", &[JValue::Object(&obj)]);
913 if jni_or_throw(&mut env, add_result, "Failed to add order to list").is_none() {
914 return JObject::null();
915 }
916 }
917
918 list
919 }
920 Err(e) => {
921 throw_exception(&mut env, &e);
922 JObject::null()
923 }
924 }
925}
926
927#[unsafe(no_mangle)]
928pub extern "system" fn Java_com_stateset_embedded_Orders_nativeUpdateStatus<'local>(
929 mut env: JNIEnv<'local>,
930 _class: JClass<'local>,
931 ptr: jlong,
932 id: JString<'local>,
933 status: JString<'local>,
934) {
935 let id_str = get_string(&mut env, &id);
936 let status_str = get_string(&mut env, &status);
937
938 let uuid = match uuid::Uuid::parse_str(&id_str) {
939 Ok(u) => u,
940 Err(_) => {
941 throw_exception(&mut env, "Invalid UUID");
942 return;
943 }
944 };
945
946 let result = use_handle(ptr, |commerce| {
948 let status = match status_str.to_lowercase().as_str() {
949 "confirmed" => OrderStatus::Confirmed,
950 "processing" => OrderStatus::Processing,
951 "shipped" => OrderStatus::Shipped,
952 "delivered" => OrderStatus::Delivered,
953 "cancelled" => OrderStatus::Cancelled,
954 _ => OrderStatus::Pending,
955 };
956 commerce.orders().update_status(uuid.into(), status).map_err(|e| e.to_string())
957 });
958
959 if let Err(e) = result {
960 throw_exception(&mut env, &e);
961 }
962}
963
964#[unsafe(no_mangle)]
969pub extern "system" fn Java_com_stateset_embedded_Carts_nativeCreate<'local>(
970 mut env: JNIEnv<'local>,
971 _class: JClass<'local>,
972 ptr: jlong,
973 customer_id: JString<'local>,
974 currency: JString<'local>,
975) -> JObject<'local> {
976 let customer_id_str = get_string(&mut env, &customer_id);
977 let currency_str = get_string(&mut env, ¤cy);
978
979 let customer_uuid = if customer_id_str.is_empty() {
980 None
981 } else {
982 uuid::Uuid::parse_str(&customer_id_str).ok()
983 };
984
985 let result = use_handle(ptr, |commerce| {
986 commerce
987 .carts()
988 .create(CreateCart {
989 customer_id: customer_uuid.map(Into::into),
990 customer_email: None,
991 customer_name: None,
992 currency: if currency_str.is_empty() { None } else { Some(currency_str) },
993 ..Default::default()
994 })
995 .map_err(|e| e.to_string())
996 });
997
998 match result {
999 Ok(cart) => create_cart_object(&mut env, &cart),
1000 Err(e) => {
1001 throw_exception(&mut env, &e);
1002 JObject::null()
1003 }
1004 }
1005}
1006
1007#[unsafe(no_mangle)]
1008pub extern "system" fn Java_com_stateset_embedded_Carts_nativeGet<'local>(
1009 mut env: JNIEnv<'local>,
1010 _class: JClass<'local>,
1011 ptr: jlong,
1012 id: JString<'local>,
1013) -> JObject<'local> {
1014 let id_str = get_string(&mut env, &id);
1015 let uuid = match uuid::Uuid::parse_str(&id_str) {
1016 Ok(u) => u,
1017 Err(_) => {
1018 throw_exception(&mut env, "Invalid UUID");
1019 return JObject::null();
1020 }
1021 };
1022
1023 let result =
1024 use_handle(ptr, |commerce| commerce.carts().get(uuid.into()).map_err(|e| e.to_string()));
1025
1026 match result {
1027 Ok(Some(cart)) => create_cart_object(&mut env, &cart),
1028 Ok(None) => JObject::null(),
1029 Err(e) => {
1030 throw_exception(&mut env, &e);
1031 JObject::null()
1032 }
1033 }
1034}
1035
1036#[unsafe(no_mangle)]
1037pub extern "system" fn Java_com_stateset_embedded_Carts_nativeAddItem<'local>(
1038 mut env: JNIEnv<'local>,
1039 _class: JClass<'local>,
1040 ptr: jlong,
1041 cart_id: JString<'local>,
1042 sku: JString<'local>,
1043 name: JString<'local>,
1044 quantity: jint,
1045 unit_price: jdouble,
1046) -> JObject<'local> {
1047 let cart_id_str = get_string(&mut env, &cart_id);
1048 let sku_str = get_string(&mut env, &sku);
1049 let name_str = get_string(&mut env, &name);
1050 let price = Decimal::try_from(unit_price).unwrap_or_default();
1051
1052 let uuid = match uuid::Uuid::parse_str(&cart_id_str) {
1053 Ok(u) => u,
1054 Err(_) => {
1055 throw_exception(&mut env, "Invalid cart UUID");
1056 return JObject::null();
1057 }
1058 };
1059
1060 let result = use_handle(ptr, |commerce| {
1061 commerce
1062 .carts()
1063 .add_item(
1064 uuid.into(),
1065 AddCartItem {
1066 sku: sku_str,
1067 name: name_str,
1068 quantity,
1069 unit_price: price,
1070 ..Default::default()
1071 },
1072 )
1073 .map_err(|e| e.to_string())?;
1074 commerce
1076 .carts()
1077 .get(uuid.into())
1078 .map_err(|e| e.to_string())?
1079 .ok_or_else(|| "Cart not found".to_string())
1080 });
1081
1082 match result {
1083 Ok(cart) => create_cart_object(&mut env, &cart),
1084 Err(e) => {
1085 throw_exception(&mut env, &e);
1086 JObject::null()
1087 }
1088 }
1089}
1090
1091#[unsafe(no_mangle)]
1092pub extern "system" fn Java_com_stateset_embedded_Carts_nativeCheckout<'local>(
1093 mut env: JNIEnv<'local>,
1094 _class: JClass<'local>,
1095 ptr: jlong,
1096 cart_id: JString<'local>,
1097) -> JObject<'local> {
1098 let cart_id_str = get_string(&mut env, &cart_id);
1099
1100 let uuid = match uuid::Uuid::parse_str(&cart_id_str) {
1101 Ok(u) => u,
1102 Err(_) => {
1103 throw_exception(&mut env, "Invalid cart UUID");
1104 return JObject::null();
1105 }
1106 };
1107
1108 let result = use_handle(ptr, |commerce| {
1109 let checkout_result = commerce.carts().complete(uuid.into()).map_err(|e| e.to_string())?;
1110 commerce
1112 .orders()
1113 .get(checkout_result.order_id)
1114 .map_err(|e| e.to_string())?
1115 .ok_or_else(|| "Order not found".to_string())
1116 });
1117
1118 match result {
1119 Ok(order) => create_order_object(&mut env, &order),
1120 Err(e) => {
1121 throw_exception(&mut env, &e);
1122 JObject::null()
1123 }
1124 }
1125}
1126
1127#[unsafe(no_mangle)]
1132pub extern "system" fn Java_com_stateset_embedded_Payments_nativeRecordPayment<'local>(
1133 mut env: JNIEnv<'local>,
1134 _class: JClass<'local>,
1135 ptr: jlong,
1136 order_id: JString<'local>,
1137 amount: jdouble,
1138 method: JString<'local>,
1139 reference: JString<'local>,
1140) {
1141 let order_id_str = get_string(&mut env, &order_id);
1142 let method_str = get_string(&mut env, &method);
1143 let reference_str = get_string(&mut env, &reference);
1144 let amt = Decimal::try_from(amount).unwrap_or_default();
1145
1146 let uuid = match uuid::Uuid::parse_str(&order_id_str) {
1147 Ok(u) => u,
1148 Err(_) => {
1149 throw_exception(&mut env, "Invalid order UUID");
1150 return;
1151 }
1152 };
1153
1154 let payment_method = match method_str.to_lowercase().as_str() {
1156 "credit" | "credit_card" | "creditcard" | "card" => PaymentMethodType::CreditCard,
1157 "debit" | "debit_card" | "debitcard" => PaymentMethodType::DebitCard,
1158 "bank" | "bank_transfer" | "banktransfer" | "ach" => PaymentMethodType::BankTransfer,
1159 "paypal" => PaymentMethodType::PayPal,
1160 "apple" | "apple_pay" | "applepay" => PaymentMethodType::ApplePay,
1161 "google" | "google_pay" | "googlepay" => PaymentMethodType::GooglePay,
1162 "crypto" | "cryptocurrency" => PaymentMethodType::Crypto,
1163 _ => PaymentMethodType::CreditCard,
1164 };
1165
1166 let result = use_handle(ptr, |commerce| {
1167 commerce
1168 .payments()
1169 .create(CreatePayment {
1170 order_id: Some(uuid.into()),
1171 amount: amt,
1172 currency: Some("USD".to_string()),
1173 payment_method,
1174 external_id: if reference_str.is_empty() { None } else { Some(reference_str) },
1175 ..Default::default()
1176 })
1177 .map_err(|e| e.to_string())
1178 });
1179
1180 if let Err(e) = result {
1181 throw_exception(&mut env, &e);
1182 }
1183}
1184
1185#[unsafe(no_mangle)]
1190pub extern "system" fn Java_com_stateset_embedded_Returns_nativeCreate<'local>(
1191 mut env: JNIEnv<'local>,
1192 _class: JClass<'local>,
1193 ptr: jlong,
1194 order_id: JString<'local>,
1195 reason: JString<'local>,
1196) -> JObject<'local> {
1197 let order_id_str = get_string(&mut env, &order_id);
1198 let reason_str = get_string(&mut env, &reason);
1199
1200 let uuid = match uuid::Uuid::parse_str(&order_id_str) {
1201 Ok(u) => u,
1202 Err(_) => {
1203 throw_exception(&mut env, "Invalid order UUID");
1204 return JObject::null();
1205 }
1206 };
1207
1208 let reason_enum = match reason_str.to_lowercase().as_str() {
1210 "defective" => ReturnReason::Defective,
1211 "wrong_item" | "wrongitem" => ReturnReason::WrongItem,
1212 "not_as_described" | "notasdescribed" => ReturnReason::NotAsDescribed,
1213 "no_longer_needed" | "nolongerneeded" => ReturnReason::NoLongerNeeded,
1214 "better_price_found" | "betterpricefound" => ReturnReason::BetterPriceFound,
1215 _ => ReturnReason::Other,
1216 };
1217
1218 let result = use_handle(ptr, |commerce| {
1219 let order = commerce.orders().get(uuid.into()).map_err(|e| e.to_string())?;
1220 let order = order.ok_or_else(|| format!("Order not found: {}", uuid))?;
1221 let items: Vec<CreateReturnItem> = order
1222 .items
1223 .iter()
1224 .map(|item| CreateReturnItem {
1225 order_item_id: item.id,
1226 quantity: item.quantity,
1227 condition: None,
1228 })
1229 .collect();
1230 if items.is_empty() {
1231 return Err("Return must have at least one item".to_string());
1232 }
1233 commerce
1234 .returns()
1235 .create(CreateReturn {
1236 order_id: uuid.into(),
1237 reason: reason_enum,
1238 items,
1239 ..Default::default()
1240 })
1241 .map_err(|e| e.to_string())
1242 });
1243
1244 match result {
1245 Ok(ret) => create_return_object(&mut env, &ret),
1246 Err(e) => {
1247 throw_exception(&mut env, &e);
1248 JObject::null()
1249 }
1250 }
1251}
1252
1253#[unsafe(no_mangle)]
1254pub extern "system" fn Java_com_stateset_embedded_Returns_nativeProcess<'local>(
1255 mut env: JNIEnv<'local>,
1256 _class: JClass<'local>,
1257 ptr: jlong,
1258 return_id: JString<'local>,
1259) {
1260 let return_id_str = get_string(&mut env, &return_id);
1261
1262 let uuid = match uuid::Uuid::parse_str(&return_id_str) {
1263 Ok(u) => u,
1264 Err(_) => {
1265 throw_exception(&mut env, "Invalid return UUID");
1266 return;
1267 }
1268 };
1269
1270 let result = use_handle(ptr, |commerce| {
1271 commerce.returns().approve(uuid.into()).map_err(|e| e.to_string())
1272 });
1273
1274 if let Err(e) = result {
1275 throw_exception(&mut env, &e);
1276 }
1277}
1278
1279#[unsafe(no_mangle)]
1280pub extern "system" fn Java_com_stateset_embedded_Returns_nativeRefund<'local>(
1281 mut env: JNIEnv<'local>,
1282 _class: JClass<'local>,
1283 ptr: jlong,
1284 return_id: JString<'local>,
1285 amount: jdouble,
1286) {
1287 let return_id_str = get_string(&mut env, &return_id);
1288 let _amt = Decimal::try_from(amount).unwrap_or_default();
1289
1290 let uuid = match uuid::Uuid::parse_str(&return_id_str) {
1291 Ok(u) => u,
1292 Err(_) => {
1293 throw_exception(&mut env, "Invalid return UUID");
1294 return;
1295 }
1296 };
1297
1298 let result = use_handle(ptr, |commerce| {
1299 commerce.returns().complete(uuid.into()).map_err(|e| e.to_string())
1300 });
1301
1302 if let Err(e) = result {
1303 throw_exception(&mut env, &e);
1304 }
1305}
1306
1307#[unsafe(no_mangle)]
1312pub extern "system" fn Java_com_stateset_embedded_Analytics_nativeSalesSummary<'local>(
1313 mut env: JNIEnv<'local>,
1314 _class: JClass<'local>,
1315 ptr: jlong,
1316 days: jint,
1317) -> JObject<'local> {
1318 let period = if days <= 0 {
1319 TimePeriod::AllTime
1320 } else if days <= 7 {
1321 TimePeriod::Last7Days
1322 } else if days <= 30 {
1323 TimePeriod::Last30Days
1324 } else if days <= 90 {
1325 TimePeriod::ThisQuarter
1326 } else {
1327 TimePeriod::AllTime
1328 };
1329
1330 let result = use_handle(ptr, |commerce| {
1331 commerce
1332 .analytics()
1333 .sales_summary(AnalyticsQuery::new().period(period))
1334 .map_err(|e| e.to_string())
1335 });
1336
1337 match result {
1338 Ok(summary) => create_sales_summary_object(&mut env, &summary),
1339 Err(e) => {
1340 throw_exception(&mut env, &e);
1341 JObject::null()
1342 }
1343 }
1344}
1345
1346fn to_json_string<'a>(env: &JNIEnv<'a>, data: &impl serde::Serialize) -> JObject<'a> {
1351 match serde_json::to_string(data) {
1352 Ok(json) => env.new_string(&json).map(|s| s.into()).unwrap_or(JObject::null()),
1353 Err(_) => JObject::null(),
1354 }
1355}
1356
1357#[unsafe(no_mangle)]
1358pub extern "system" fn Java_com_stateset_embedded_Quality_nativeCreateInspection<'local>(
1359 mut env: JNIEnv<'local>,
1360 _class: JClass<'local>,
1361 ptr: jlong,
1362 sku: JString<'local>,
1363 inspection_type: JString<'local>,
1364 quantity: jdouble,
1365) -> JObject<'local> {
1366 let sku_str = get_string(&mut env, &sku);
1367 let type_str = get_string(&mut env, &inspection_type);
1368 let qty = Decimal::try_from(quantity).unwrap_or_default();
1369
1370 let itype = match type_str.to_lowercase().as_str() {
1371 "incoming" => stateset_core::InspectionType::Incoming,
1372 "in_process" => stateset_core::InspectionType::InProcess,
1373 "final" => stateset_core::InspectionType::Final,
1374 "random" => stateset_core::InspectionType::Random,
1375 _ => stateset_core::InspectionType::Incoming,
1376 };
1377
1378 let result = use_handle(ptr, |commerce| {
1379 commerce
1380 .quality()
1381 .create_inspection(stateset_core::CreateInspection {
1382 inspection_type: itype,
1383 reference_type: sku_str.clone(),
1384 reference_id: uuid::Uuid::new_v4(),
1385 items: vec![stateset_core::CreateInspectionItem {
1386 sku: sku_str,
1387 quantity_to_inspect: qty,
1388 ..Default::default()
1389 }],
1390 ..Default::default()
1391 })
1392 .map_err(|e| e.to_string())
1393 });
1394
1395 match result {
1396 Ok(inspection) => to_json_string(&env, &inspection),
1397 Err(e) => {
1398 throw_exception(&mut env, &e);
1399 JObject::null()
1400 }
1401 }
1402}
1403
1404#[unsafe(no_mangle)]
1405pub extern "system" fn Java_com_stateset_embedded_Quality_nativeListInspections<'local>(
1406 mut env: JNIEnv<'local>,
1407 _class: JClass<'local>,
1408 ptr: jlong,
1409) -> JObject<'local> {
1410 let result = use_handle(ptr, |commerce| {
1411 commerce.quality().list_inspections(Default::default()).map_err(|e| e.to_string())
1412 });
1413 match result {
1414 Ok(inspections) => to_json_string(&env, &inspections),
1415 Err(e) => {
1416 throw_exception(&mut env, &e);
1417 JObject::null()
1418 }
1419 }
1420}
1421
1422#[unsafe(no_mangle)]
1423pub extern "system" fn Java_com_stateset_embedded_Quality_nativeCreateNcr<'local>(
1424 mut env: JNIEnv<'local>,
1425 _class: JClass<'local>,
1426 ptr: jlong,
1427 sku: JString<'local>,
1428 description: JString<'local>,
1429 quantity: jdouble,
1430) -> JObject<'local> {
1431 let sku_str = get_string(&mut env, &sku);
1432 let desc_str = get_string(&mut env, &description);
1433 let qty = Decimal::try_from(quantity).unwrap_or_default();
1434
1435 let result = use_handle(ptr, |commerce| {
1436 commerce
1437 .quality()
1438 .create_ncr(stateset_core::CreateNcr {
1439 sku: sku_str,
1440 description: desc_str,
1441 quantity_affected: qty,
1442 ..Default::default()
1443 })
1444 .map_err(|e| e.to_string())
1445 });
1446
1447 match result {
1448 Ok(ncr) => to_json_string(&env, &ncr),
1449 Err(e) => {
1450 throw_exception(&mut env, &e);
1451 JObject::null()
1452 }
1453 }
1454}
1455
1456#[unsafe(no_mangle)]
1457pub extern "system" fn Java_com_stateset_embedded_Quality_nativeCreateHold<'local>(
1458 mut env: JNIEnv<'local>,
1459 _class: JClass<'local>,
1460 ptr: jlong,
1461 sku: JString<'local>,
1462 reason: JString<'local>,
1463 quantity: jdouble,
1464) -> JObject<'local> {
1465 let sku_str = get_string(&mut env, &sku);
1466 let reason_str = get_string(&mut env, &reason);
1467 let qty = Decimal::try_from(quantity).unwrap_or_default();
1468
1469 let result = use_handle(ptr, |commerce| {
1470 commerce
1471 .quality()
1472 .create_hold(stateset_core::CreateQualityHold {
1473 sku: sku_str,
1474 reason: reason_str,
1475 quantity: qty,
1476 ..Default::default()
1477 })
1478 .map_err(|e| e.to_string())
1479 });
1480
1481 match result {
1482 Ok(hold) => to_json_string(&env, &hold),
1483 Err(e) => {
1484 throw_exception(&mut env, &e);
1485 JObject::null()
1486 }
1487 }
1488}
1489
1490#[unsafe(no_mangle)]
1495pub extern "system" fn Java_com_stateset_embedded_Lots_nativeCreate<'local>(
1496 mut env: JNIEnv<'local>,
1497 _class: JClass<'local>,
1498 ptr: jlong,
1499 sku: JString<'local>,
1500 lot_number: JString<'local>,
1501 quantity: jdouble,
1502) -> JObject<'local> {
1503 let sku_str = get_string(&mut env, &sku);
1504 let lot_str = get_string(&mut env, &lot_number);
1505 let qty = Decimal::try_from(quantity).unwrap_or_default();
1506
1507 let result = use_handle(ptr, |commerce| {
1508 commerce
1509 .lots()
1510 .create(stateset_core::CreateLot {
1511 sku: sku_str,
1512 lot_number: Some(lot_str),
1513 quantity: qty,
1514 ..Default::default()
1515 })
1516 .map_err(|e| e.to_string())
1517 });
1518
1519 match result {
1520 Ok(lot) => to_json_string(&env, &lot),
1521 Err(e) => {
1522 throw_exception(&mut env, &e);
1523 JObject::null()
1524 }
1525 }
1526}
1527
1528#[unsafe(no_mangle)]
1529pub extern "system" fn Java_com_stateset_embedded_Lots_nativeList<'local>(
1530 mut env: JNIEnv<'local>,
1531 _class: JClass<'local>,
1532 ptr: jlong,
1533) -> JObject<'local> {
1534 let result = use_handle(ptr, |commerce| {
1535 commerce.lots().list(Default::default()).map_err(|e| e.to_string())
1536 });
1537 match result {
1538 Ok(lots) => to_json_string(&env, &lots),
1539 Err(e) => {
1540 throw_exception(&mut env, &e);
1541 JObject::null()
1542 }
1543 }
1544}
1545
1546#[unsafe(no_mangle)]
1547pub extern "system" fn Java_com_stateset_embedded_Lots_nativeGetBySku<'local>(
1548 mut env: JNIEnv<'local>,
1549 _class: JClass<'local>,
1550 ptr: jlong,
1551 sku: JString<'local>,
1552) -> JObject<'local> {
1553 let sku_str = get_string(&mut env, &sku);
1554 let result = use_handle(ptr, |commerce| {
1555 commerce.lots().get_available_lots_for_sku(&sku_str).map_err(|e| e.to_string())
1556 });
1557 match result {
1558 Ok(lots) => to_json_string(&env, &lots),
1559 Err(e) => {
1560 throw_exception(&mut env, &e);
1561 JObject::null()
1562 }
1563 }
1564}
1565
1566#[unsafe(no_mangle)]
1567pub extern "system" fn Java_com_stateset_embedded_Lots_nativeGetExpiring<'local>(
1568 mut env: JNIEnv<'local>,
1569 _class: JClass<'local>,
1570 ptr: jlong,
1571 days: jint,
1572) -> JObject<'local> {
1573 let result = use_handle(ptr, |commerce| {
1574 commerce.lots().get_expiring_lots(days).map_err(|e| e.to_string())
1575 });
1576 match result {
1577 Ok(lots) => to_json_string(&env, &lots),
1578 Err(e) => {
1579 throw_exception(&mut env, &e);
1580 JObject::null()
1581 }
1582 }
1583}
1584
1585#[unsafe(no_mangle)]
1590pub extern "system" fn Java_com_stateset_embedded_Serials_nativeCreate<'local>(
1591 mut env: JNIEnv<'local>,
1592 _class: JClass<'local>,
1593 ptr: jlong,
1594 sku: JString<'local>,
1595 serial_number: JString<'local>,
1596) -> JObject<'local> {
1597 let sku_str = get_string(&mut env, &sku);
1598 let serial_str = get_string(&mut env, &serial_number);
1599
1600 let result = use_handle(ptr, |commerce| {
1601 commerce
1602 .serials()
1603 .create(stateset_core::CreateSerialNumber {
1604 sku: sku_str,
1605 serial: Some(serial_str),
1606 ..Default::default()
1607 })
1608 .map_err(|e| e.to_string())
1609 });
1610
1611 match result {
1612 Ok(serial) => to_json_string(&env, &serial),
1613 Err(e) => {
1614 throw_exception(&mut env, &e);
1615 JObject::null()
1616 }
1617 }
1618}
1619
1620#[unsafe(no_mangle)]
1621pub extern "system" fn Java_com_stateset_embedded_Serials_nativeList<'local>(
1622 mut env: JNIEnv<'local>,
1623 _class: JClass<'local>,
1624 ptr: jlong,
1625) -> JObject<'local> {
1626 let result = use_handle(ptr, |commerce| {
1627 commerce.serials().list(Default::default()).map_err(|e| e.to_string())
1628 });
1629 match result {
1630 Ok(serials) => to_json_string(&env, &serials),
1631 Err(e) => {
1632 throw_exception(&mut env, &e);
1633 JObject::null()
1634 }
1635 }
1636}
1637
1638#[unsafe(no_mangle)]
1639pub extern "system" fn Java_com_stateset_embedded_Serials_nativeGetByNumber<'local>(
1640 mut env: JNIEnv<'local>,
1641 _class: JClass<'local>,
1642 ptr: jlong,
1643 serial_number: JString<'local>,
1644) -> JObject<'local> {
1645 let serial_str = get_string(&mut env, &serial_number);
1646 let result = use_handle(ptr, |commerce| {
1647 commerce.serials().get_by_serial(&serial_str).map_err(|e| e.to_string())
1648 });
1649 match result {
1650 Ok(Some(serial)) => to_json_string(&env, &serial),
1651 Ok(None) => JObject::null(),
1652 Err(e) => {
1653 throw_exception(&mut env, &e);
1654 JObject::null()
1655 }
1656 }
1657}
1658
1659#[unsafe(no_mangle)]
1664pub extern "system" fn Java_com_stateset_embedded_Warehouse_nativeCreate<'local>(
1665 mut env: JNIEnv<'local>,
1666 _class: JClass<'local>,
1667 ptr: jlong,
1668 code: JString<'local>,
1669 name: JString<'local>,
1670) -> JObject<'local> {
1671 let code_str = get_string(&mut env, &code);
1672 let name_str = get_string(&mut env, &name);
1673
1674 let result = use_handle(ptr, |commerce| {
1675 commerce
1676 .warehouse()
1677 .create_warehouse(stateset_core::CreateWarehouse {
1678 code: code_str,
1679 name: name_str,
1680 ..Default::default()
1681 })
1682 .map_err(|e| e.to_string())
1683 });
1684
1685 match result {
1686 Ok(warehouse) => to_json_string(&env, &warehouse),
1687 Err(e) => {
1688 throw_exception(&mut env, &e);
1689 JObject::null()
1690 }
1691 }
1692}
1693
1694#[unsafe(no_mangle)]
1695pub extern "system" fn Java_com_stateset_embedded_Warehouse_nativeList<'local>(
1696 mut env: JNIEnv<'local>,
1697 _class: JClass<'local>,
1698 ptr: jlong,
1699) -> JObject<'local> {
1700 let result = use_handle(ptr, |commerce| {
1701 commerce.warehouse().list_warehouses(Default::default()).map_err(|e| e.to_string())
1702 });
1703 match result {
1704 Ok(warehouses) => to_json_string(&env, &warehouses),
1705 Err(e) => {
1706 throw_exception(&mut env, &e);
1707 JObject::null()
1708 }
1709 }
1710}
1711
1712#[unsafe(no_mangle)]
1713pub extern "system" fn Java_com_stateset_embedded_Warehouse_nativeCreateLocation<'local>(
1714 mut env: JNIEnv<'local>,
1715 _class: JClass<'local>,
1716 ptr: jlong,
1717 warehouse_id: jint,
1718 code: JString<'local>,
1719) -> JObject<'local> {
1720 let code_str = get_string(&mut env, &code);
1721
1722 let result = use_handle(ptr, |commerce| {
1723 commerce
1724 .warehouse()
1725 .create_location(stateset_core::CreateLocation {
1726 warehouse_id,
1727 code: Some(code_str),
1728 ..Default::default()
1729 })
1730 .map_err(|e| e.to_string())
1731 });
1732
1733 match result {
1734 Ok(location) => to_json_string(&env, &location),
1735 Err(e) => {
1736 throw_exception(&mut env, &e);
1737 JObject::null()
1738 }
1739 }
1740}
1741
1742#[unsafe(no_mangle)]
1747pub extern "system" fn Java_com_stateset_embedded_Receiving_nativeCreateReceipt<'local>(
1748 mut env: JNIEnv<'local>,
1749 _class: JClass<'local>,
1750 ptr: jlong,
1751) -> JObject<'local> {
1752 let result = use_handle(ptr, |commerce| {
1753 commerce
1754 .receiving()
1755 .create_receipt(stateset_core::CreateReceipt::default())
1756 .map_err(|e| e.to_string())
1757 });
1758
1759 match result {
1760 Ok(receipt) => to_json_string(&env, &receipt),
1761 Err(e) => {
1762 throw_exception(&mut env, &e);
1763 JObject::null()
1764 }
1765 }
1766}
1767
1768#[unsafe(no_mangle)]
1769pub extern "system" fn Java_com_stateset_embedded_Receiving_nativeListReceipts<'local>(
1770 mut env: JNIEnv<'local>,
1771 _class: JClass<'local>,
1772 ptr: jlong,
1773) -> JObject<'local> {
1774 let result = use_handle(ptr, |commerce| {
1775 commerce.receiving().list_receipts(Default::default()).map_err(|e| e.to_string())
1776 });
1777 match result {
1778 Ok(receipts) => to_json_string(&env, &receipts),
1779 Err(e) => {
1780 throw_exception(&mut env, &e);
1781 JObject::null()
1782 }
1783 }
1784}
1785
1786#[unsafe(no_mangle)]
1787pub extern "system" fn Java_com_stateset_embedded_Receiving_nativeAddLine<'local>(
1788 mut env: JNIEnv<'local>,
1789 _class: JClass<'local>,
1790 ptr: jlong,
1791 receipt_id: JString<'local>,
1792 sku: JString<'local>,
1793 quantity: jdouble,
1794) -> JObject<'local> {
1795 let receipt_id_str = get_string(&mut env, &receipt_id);
1796 let sku_str = get_string(&mut env, &sku);
1797 let qty = Decimal::try_from(quantity).unwrap_or_default();
1798
1799 let uuid = match uuid::Uuid::parse_str(&receipt_id_str) {
1800 Ok(u) => u,
1801 Err(_) => {
1802 throw_exception(&mut env, "Invalid UUID");
1803 return JObject::null();
1804 }
1805 };
1806
1807 let result = use_handle(ptr, |commerce| {
1810 commerce
1811 .receiving()
1812 .receive_items(stateset_core::ReceiveItems {
1813 receipt_id: uuid,
1814 items: vec![stateset_core::ReceiveItemLine {
1815 receipt_item_id: uuid::Uuid::new_v4(),
1816 quantity_received: qty,
1817 quantity_rejected: Some(Decimal::ZERO),
1818 rejection_reason: None,
1819 lot_number: None,
1820 serial_numbers: None,
1821 expiration_date: None,
1822 notes: Some(sku_str),
1823 }],
1824 receiving_location_id: None,
1825 received_by: None,
1826 })
1827 .map_err(|e| e.to_string())
1828 });
1829
1830 match result {
1831 Ok(line) => to_json_string(&env, &line),
1832 Err(e) => {
1833 throw_exception(&mut env, &e);
1834 JObject::null()
1835 }
1836 }
1837}
1838
1839#[unsafe(no_mangle)]
1840pub extern "system" fn Java_com_stateset_embedded_Receiving_nativeComplete<'local>(
1841 mut env: JNIEnv<'local>,
1842 _class: JClass<'local>,
1843 ptr: jlong,
1844 receipt_id: JString<'local>,
1845) -> JObject<'local> {
1846 let receipt_id_str = get_string(&mut env, &receipt_id);
1847 let uuid = match uuid::Uuid::parse_str(&receipt_id_str) {
1848 Ok(u) => u,
1849 Err(_) => {
1850 throw_exception(&mut env, "Invalid UUID");
1851 return JObject::null();
1852 }
1853 };
1854
1855 let result = use_handle(ptr, |commerce| {
1856 commerce.receiving().complete_receiving(uuid).map_err(|e| e.to_string())
1857 });
1858
1859 match result {
1860 Ok(receipt) => to_json_string(&env, &receipt),
1861 Err(e) => {
1862 throw_exception(&mut env, &e);
1863 JObject::null()
1864 }
1865 }
1866}
1867
1868#[unsafe(no_mangle)]
1873pub extern "system" fn Java_com_stateset_embedded_Fulfillment_nativeCreateWave<'local>(
1874 mut env: JNIEnv<'local>,
1875 _class: JClass<'local>,
1876 ptr: jlong,
1877 warehouse_id: jint,
1878) -> JObject<'local> {
1879 let result = use_handle(ptr, |commerce| {
1880 commerce
1881 .fulfillment()
1882 .create_wave(stateset_core::CreateWave { warehouse_id, ..Default::default() })
1883 .map_err(|e| e.to_string())
1884 });
1885
1886 match result {
1887 Ok(wave) => to_json_string(&env, &wave),
1888 Err(e) => {
1889 throw_exception(&mut env, &e);
1890 JObject::null()
1891 }
1892 }
1893}
1894
1895#[unsafe(no_mangle)]
1896pub extern "system" fn Java_com_stateset_embedded_Fulfillment_nativeListWaves<'local>(
1897 mut env: JNIEnv<'local>,
1898 _class: JClass<'local>,
1899 ptr: jlong,
1900) -> JObject<'local> {
1901 let result = use_handle(ptr, |commerce| {
1902 commerce.fulfillment().list_waves(Default::default()).map_err(|e| e.to_string())
1903 });
1904 match result {
1905 Ok(waves) => to_json_string(&env, &waves),
1906 Err(e) => {
1907 throw_exception(&mut env, &e);
1908 JObject::null()
1909 }
1910 }
1911}
1912
1913#[unsafe(no_mangle)]
1914pub extern "system" fn Java_com_stateset_embedded_Fulfillment_nativeCreatePickTask<'local>(
1915 mut env: JNIEnv<'local>,
1916 _class: JClass<'local>,
1917 ptr: jlong,
1918 order_id: JString<'local>,
1919 warehouse_id: jint,
1920) -> JObject<'local> {
1921 let order_id_str = get_string(&mut env, &order_id);
1922
1923 let uuid = match uuid::Uuid::parse_str(&order_id_str) {
1924 Ok(u) => u,
1925 Err(_) => {
1926 throw_exception(&mut env, "Invalid UUID");
1927 return JObject::null();
1928 }
1929 };
1930
1931 let result = use_handle(ptr, |commerce| {
1933 commerce
1934 .fulfillment()
1935 .create_picks_for_order(uuid.into(), warehouse_id)
1936 .map_err(|e| e.to_string())
1937 });
1938
1939 match result {
1940 Ok(tasks) => to_json_string(&env, &tasks),
1941 Err(e) => {
1942 throw_exception(&mut env, &e);
1943 JObject::null()
1944 }
1945 }
1946}
1947
1948#[unsafe(no_mangle)]
1953pub extern "system" fn Java_com_stateset_embedded_AccountsPayable_nativeCreateBill<'local>(
1954 mut env: JNIEnv<'local>,
1955 _class: JClass<'local>,
1956 ptr: jlong,
1957 supplier_id: JString<'local>,
1958 amount: jdouble,
1959) -> JObject<'local> {
1960 let supplier_id_str = get_string(&mut env, &supplier_id);
1961 let amt = Decimal::try_from(amount).unwrap_or_default();
1962
1963 let uuid = match uuid::Uuid::parse_str(&supplier_id_str) {
1964 Ok(u) => u,
1965 Err(_) => {
1966 throw_exception(&mut env, "Invalid UUID");
1967 return JObject::null();
1968 }
1969 };
1970
1971 let result = use_handle(ptr, |commerce| {
1972 commerce
1973 .accounts_payable()
1974 .create_bill(stateset_core::CreateBill {
1975 supplier_id: uuid,
1976 due_date: chrono::Utc::now() + chrono::Duration::days(30),
1977 items: vec![stateset_core::CreateBillItem {
1978 description: "Bill amount".to_string(),
1979 quantity: Decimal::from(1),
1980 unit_price: amt,
1981 ..Default::default()
1982 }],
1983 ..Default::default()
1984 })
1985 .map_err(|e| e.to_string())
1986 });
1987
1988 match result {
1989 Ok(bill) => to_json_string(&env, &bill),
1990 Err(e) => {
1991 throw_exception(&mut env, &e);
1992 JObject::null()
1993 }
1994 }
1995}
1996
1997#[unsafe(no_mangle)]
1998pub extern "system" fn Java_com_stateset_embedded_AccountsPayable_nativeListBills<'local>(
1999 mut env: JNIEnv<'local>,
2000 _class: JClass<'local>,
2001 ptr: jlong,
2002) -> JObject<'local> {
2003 let result = use_handle(ptr, |commerce| {
2004 commerce.accounts_payable().list_bills(Default::default()).map_err(|e| e.to_string())
2005 });
2006 match result {
2007 Ok(bills) => to_json_string(&env, &bills),
2008 Err(e) => {
2009 throw_exception(&mut env, &e);
2010 JObject::null()
2011 }
2012 }
2013}
2014
2015#[unsafe(no_mangle)]
2016pub extern "system" fn Java_com_stateset_embedded_AccountsPayable_nativeGetAgingSummary<'local>(
2017 mut env: JNIEnv<'local>,
2018 _class: JClass<'local>,
2019 ptr: jlong,
2020) -> JObject<'local> {
2021 let result = use_handle(ptr, |commerce| {
2022 commerce.accounts_payable().get_aging_summary().map_err(|e| e.to_string())
2023 });
2024 match result {
2025 Ok(summary) => to_json_string(&env, &summary),
2026 Err(e) => {
2027 throw_exception(&mut env, &e);
2028 JObject::null()
2029 }
2030 }
2031}
2032
2033#[unsafe(no_mangle)]
2038pub extern "system" fn Java_com_stateset_embedded_AccountsReceivable_nativeGetAgingSummary<
2039 'local,
2040>(
2041 mut env: JNIEnv<'local>,
2042 _class: JClass<'local>,
2043 ptr: jlong,
2044) -> JObject<'local> {
2045 let result = use_handle(ptr, |commerce| {
2046 commerce.accounts_receivable().get_aging_summary().map_err(|e| e.to_string())
2047 });
2048 match result {
2049 Ok(summary) => to_json_string(&env, &summary),
2050 Err(e) => {
2051 throw_exception(&mut env, &e);
2052 JObject::null()
2053 }
2054 }
2055}
2056
2057#[unsafe(no_mangle)]
2058pub extern "system" fn Java_com_stateset_embedded_AccountsReceivable_nativeGetDso<'local>(
2059 mut env: JNIEnv<'local>,
2060 _class: JClass<'local>,
2061 ptr: jlong,
2062 days: jint,
2063) -> jdouble {
2064 let result = use_handle(ptr, |commerce| {
2065 commerce.accounts_receivable().get_dso(days).map_err(|e| e.to_string())
2066 });
2067 match result {
2068 Ok(dso) => to_f64_or_nan(dso),
2069 Err(e) => {
2070 throw_exception(&mut env, &e);
2071 0.0
2072 }
2073 }
2074}
2075
2076#[unsafe(no_mangle)]
2077pub extern "system" fn Java_com_stateset_embedded_AccountsReceivable_nativeCreateCreditMemo<
2078 'local,
2079>(
2080 mut env: JNIEnv<'local>,
2081 _class: JClass<'local>,
2082 ptr: jlong,
2083 customer_id: JString<'local>,
2084 amount: jdouble,
2085 reason: JString<'local>,
2086) -> JObject<'local> {
2087 let customer_id_str = get_string(&mut env, &customer_id);
2088 let reason_str = get_string(&mut env, &reason);
2089 let amt = Decimal::try_from(amount).unwrap_or_default();
2090
2091 let uuid = match uuid::Uuid::parse_str(&customer_id_str) {
2092 Ok(u) => u,
2093 Err(_) => {
2094 throw_exception(&mut env, "Invalid UUID");
2095 return JObject::null();
2096 }
2097 };
2098
2099 let memo_reason = match reason_str.to_lowercase().as_str() {
2101 "returned_goods" | "return" => stateset_core::CreditMemoReason::ReturnedGoods,
2102 "pricing_error" | "pricing" => stateset_core::CreditMemoReason::PricingError,
2103 "overpayment" => stateset_core::CreditMemoReason::Overpayment,
2104 "damaged" => stateset_core::CreditMemoReason::Damaged,
2105 "service_credit" | "service" => stateset_core::CreditMemoReason::ServiceCredit,
2106 "goodwill" | "goodwill_adjustment" => stateset_core::CreditMemoReason::GoodwillAdjustment,
2107 _ => stateset_core::CreditMemoReason::Other,
2108 };
2109
2110 let result = use_handle(ptr, |commerce| {
2111 commerce
2112 .accounts_receivable()
2113 .create_credit_memo(stateset_core::CreateCreditMemo {
2114 customer_id: uuid,
2115 original_invoice_id: None,
2116 reason: memo_reason,
2117 amount: amt,
2118 notes: None,
2119 })
2120 .map_err(|e| e.to_string())
2121 });
2122
2123 match result {
2124 Ok(memo) => to_json_string(&env, &memo),
2125 Err(e) => {
2126 throw_exception(&mut env, &e);
2127 JObject::null()
2128 }
2129 }
2130}
2131
2132#[unsafe(no_mangle)]
2137pub extern "system" fn Java_com_stateset_embedded_CostAccounting_nativeGetItemCost<'local>(
2138 mut env: JNIEnv<'local>,
2139 _class: JClass<'local>,
2140 ptr: jlong,
2141 sku: JString<'local>,
2142) -> JObject<'local> {
2143 let sku_str = get_string(&mut env, &sku);
2144 let result = use_handle(ptr, |commerce| {
2145 commerce.cost_accounting().get_item_cost(&sku_str).map_err(|e| e.to_string())
2146 });
2147 match result {
2148 Ok(Some(cost)) => to_json_string(&env, &cost),
2149 Ok(None) => JObject::null(),
2150 Err(e) => {
2151 throw_exception(&mut env, &e);
2152 JObject::null()
2153 }
2154 }
2155}
2156
2157#[unsafe(no_mangle)]
2158pub extern "system" fn Java_com_stateset_embedded_CostAccounting_nativeSetItemCost<'local>(
2159 mut env: JNIEnv<'local>,
2160 _class: JClass<'local>,
2161 ptr: jlong,
2162 sku: JString<'local>,
2163 standard_cost: jdouble,
2164) -> JObject<'local> {
2165 let sku_str = get_string(&mut env, &sku);
2166 let cost = Decimal::try_from(standard_cost).ok();
2167
2168 let result = use_handle(ptr, |commerce| {
2169 commerce
2170 .cost_accounting()
2171 .set_item_cost(stateset_core::SetItemCost {
2172 sku: sku_str,
2173 standard_cost: cost,
2174 ..Default::default()
2175 })
2176 .map_err(|e| e.to_string())
2177 });
2178
2179 match result {
2180 Ok(item_cost) => to_json_string(&env, &item_cost),
2181 Err(e) => {
2182 throw_exception(&mut env, &e);
2183 JObject::null()
2184 }
2185 }
2186}
2187
2188#[unsafe(no_mangle)]
2189pub extern "system" fn Java_com_stateset_embedded_CostAccounting_nativeGetTotalInventoryValue<
2190 'local,
2191>(
2192 mut env: JNIEnv<'local>,
2193 _class: JClass<'local>,
2194 ptr: jlong,
2195) -> jdouble {
2196 let result = use_handle(ptr, |commerce| {
2197 commerce.cost_accounting().get_total_inventory_value().map_err(|e| e.to_string())
2198 });
2199 match result {
2200 Ok(value) => to_f64_or_nan(value),
2201 Err(e) => {
2202 throw_exception(&mut env, &e);
2203 0.0
2204 }
2205 }
2206}
2207
2208#[unsafe(no_mangle)]
2213pub extern "system" fn Java_com_stateset_embedded_Credit_nativeCreateAccount<'local>(
2214 mut env: JNIEnv<'local>,
2215 _class: JClass<'local>,
2216 ptr: jlong,
2217 customer_id: JString<'local>,
2218 credit_limit: jdouble,
2219) -> JObject<'local> {
2220 let customer_id_str = get_string(&mut env, &customer_id);
2221 let limit = Decimal::try_from(credit_limit).unwrap_or_default();
2222
2223 let uuid = match uuid::Uuid::parse_str(&customer_id_str) {
2224 Ok(u) => u,
2225 Err(_) => {
2226 throw_exception(&mut env, "Invalid UUID");
2227 return JObject::null();
2228 }
2229 };
2230
2231 let result = use_handle(ptr, |commerce| {
2232 commerce
2233 .credit()
2234 .create_credit_account(stateset_core::CreateCreditAccount {
2235 customer_id: uuid.into(),
2236 credit_limit: limit,
2237 ..Default::default()
2238 })
2239 .map_err(|e| e.to_string())
2240 });
2241
2242 match result {
2243 Ok(account) => to_json_string(&env, &account),
2244 Err(e) => {
2245 throw_exception(&mut env, &e);
2246 JObject::null()
2247 }
2248 }
2249}
2250
2251#[unsafe(no_mangle)]
2252pub extern "system" fn Java_com_stateset_embedded_Credit_nativeCheckCredit<'local>(
2253 mut env: JNIEnv<'local>,
2254 _class: JClass<'local>,
2255 ptr: jlong,
2256 customer_id: JString<'local>,
2257 order_amount: jdouble,
2258) -> JObject<'local> {
2259 let customer_id_str = get_string(&mut env, &customer_id);
2260 let amount = Decimal::try_from(order_amount).unwrap_or_default();
2261
2262 let uuid = match uuid::Uuid::parse_str(&customer_id_str) {
2263 Ok(u) => u,
2264 Err(_) => {
2265 throw_exception(&mut env, "Invalid UUID");
2266 return JObject::null();
2267 }
2268 };
2269
2270 let result = use_handle(ptr, |commerce| {
2271 commerce.credit().check_credit(uuid.into(), amount).map_err(|e| e.to_string())
2272 });
2273
2274 match result {
2275 Ok(check_result) => to_json_string(&env, &check_result),
2276 Err(e) => {
2277 throw_exception(&mut env, &e);
2278 JObject::null()
2279 }
2280 }
2281}
2282
2283#[unsafe(no_mangle)]
2284pub extern "system" fn Java_com_stateset_embedded_Credit_nativeGetOverLimitCustomers<'local>(
2285 mut env: JNIEnv<'local>,
2286 _class: JClass<'local>,
2287 ptr: jlong,
2288) -> JObject<'local> {
2289 let result = use_handle(ptr, |commerce| {
2290 commerce.credit().get_over_limit_customers().map_err(|e| e.to_string())
2291 });
2292 match result {
2293 Ok(customers) => to_json_string(&env, &customers),
2294 Err(e) => {
2295 throw_exception(&mut env, &e);
2296 JObject::null()
2297 }
2298 }
2299}
2300
2301#[unsafe(no_mangle)]
2306pub extern "system" fn Java_com_stateset_embedded_Backorders_nativeCreate<'local>(
2307 mut env: JNIEnv<'local>,
2308 _class: JClass<'local>,
2309 ptr: jlong,
2310 order_id: JString<'local>,
2311 customer_id: JString<'local>,
2312 sku: JString<'local>,
2313 quantity: jdouble,
2314) -> JObject<'local> {
2315 let order_id_str = get_string(&mut env, &order_id);
2316 let customer_id_str = get_string(&mut env, &customer_id);
2317 let sku_str = get_string(&mut env, &sku);
2318 let qty = Decimal::try_from(quantity).unwrap_or_default();
2319
2320 let order_uuid = match uuid::Uuid::parse_str(&order_id_str) {
2321 Ok(u) => u,
2322 Err(_) => {
2323 throw_exception(&mut env, "Invalid order UUID");
2324 return JObject::null();
2325 }
2326 };
2327 let customer_uuid = match uuid::Uuid::parse_str(&customer_id_str) {
2328 Ok(u) => u,
2329 Err(_) => {
2330 throw_exception(&mut env, "Invalid customer UUID");
2331 return JObject::null();
2332 }
2333 };
2334
2335 let result = use_handle(ptr, |commerce| {
2336 commerce
2337 .backorder()
2338 .create_backorder(stateset_core::CreateBackorder {
2339 order_id: order_uuid,
2340 order_line_id: None,
2341 customer_id: customer_uuid,
2342 sku: sku_str,
2343 quantity: qty,
2344 priority: None,
2345 expected_date: None,
2346 promised_date: None,
2347 source_location_id: None,
2348 notes: None,
2349 })
2350 .map_err(|e| e.to_string())
2351 });
2352
2353 match result {
2354 Ok(backorder) => to_json_string(&env, &backorder),
2355 Err(e) => {
2356 throw_exception(&mut env, &e);
2357 JObject::null()
2358 }
2359 }
2360}
2361
2362#[unsafe(no_mangle)]
2363pub extern "system" fn Java_com_stateset_embedded_Backorders_nativeList<'local>(
2364 mut env: JNIEnv<'local>,
2365 _class: JClass<'local>,
2366 ptr: jlong,
2367) -> JObject<'local> {
2368 let result = use_handle(ptr, |commerce| {
2369 commerce.backorder().list_backorders(Default::default()).map_err(|e| e.to_string())
2370 });
2371 match result {
2372 Ok(backorders) => to_json_string(&env, &backorders),
2373 Err(e) => {
2374 throw_exception(&mut env, &e);
2375 JObject::null()
2376 }
2377 }
2378}
2379
2380#[unsafe(no_mangle)]
2381pub extern "system" fn Java_com_stateset_embedded_Backorders_nativeGetSummary<'local>(
2382 mut env: JNIEnv<'local>,
2383 _class: JClass<'local>,
2384 ptr: jlong,
2385) -> JObject<'local> {
2386 let result =
2387 use_handle(ptr, |commerce| commerce.backorder().get_summary().map_err(|e| e.to_string()));
2388 match result {
2389 Ok(summary) => to_json_string(&env, &summary),
2390 Err(e) => {
2391 throw_exception(&mut env, &e);
2392 JObject::null()
2393 }
2394 }
2395}
2396
2397#[unsafe(no_mangle)]
2398pub extern "system" fn Java_com_stateset_embedded_Backorders_nativeGetOverdue<'local>(
2399 mut env: JNIEnv<'local>,
2400 _class: JClass<'local>,
2401 ptr: jlong,
2402) -> JObject<'local> {
2403 let result = use_handle(ptr, |commerce| {
2404 commerce.backorder().get_overdue_backorders().map_err(|e| e.to_string())
2405 });
2406 match result {
2407 Ok(backorders) => to_json_string(&env, &backorders),
2408 Err(e) => {
2409 throw_exception(&mut env, &e);
2410 JObject::null()
2411 }
2412 }
2413}
2414
2415#[unsafe(no_mangle)]
2420pub extern "system" fn Java_com_stateset_embedded_GeneralLedger_nativeCreateAccount<'local>(
2421 mut env: JNIEnv<'local>,
2422 _class: JClass<'local>,
2423 ptr: jlong,
2424 account_number: JString<'local>,
2425 name: JString<'local>,
2426 account_type: JString<'local>,
2427) -> JObject<'local> {
2428 let number_str = get_string(&mut env, &account_number);
2429 let name_str = get_string(&mut env, &name);
2430 let type_str = get_string(&mut env, &account_type);
2431
2432 let acct_type = match type_str.to_lowercase().as_str() {
2433 "asset" => stateset_core::AccountType::Asset,
2434 "liability" => stateset_core::AccountType::Liability,
2435 "equity" => stateset_core::AccountType::Equity,
2436 "revenue" => stateset_core::AccountType::Revenue,
2437 "expense" => stateset_core::AccountType::Expense,
2438 _ => stateset_core::AccountType::Asset,
2439 };
2440
2441 let result = use_handle(ptr, |commerce| {
2442 commerce
2443 .general_ledger()
2444 .create_account(stateset_core::CreateGlAccount {
2445 account_number: number_str,
2446 name: name_str,
2447 description: None,
2448 account_type: acct_type,
2449 account_sub_type: None,
2450 parent_account_id: None,
2451 is_header: None,
2452 is_posting: None,
2453 currency: None,
2454 })
2455 .map_err(|e| e.to_string())
2456 });
2457
2458 match result {
2459 Ok(account) => to_json_string(&env, &account),
2460 Err(e) => {
2461 throw_exception(&mut env, &e);
2462 JObject::null()
2463 }
2464 }
2465}
2466
2467#[unsafe(no_mangle)]
2468pub extern "system" fn Java_com_stateset_embedded_GeneralLedger_nativeListAccounts<'local>(
2469 mut env: JNIEnv<'local>,
2470 _class: JClass<'local>,
2471 ptr: jlong,
2472) -> JObject<'local> {
2473 let result = use_handle(ptr, |commerce| {
2474 commerce.general_ledger().list_accounts(Default::default()).map_err(|e| e.to_string())
2475 });
2476 match result {
2477 Ok(accounts) => to_json_string(&env, &accounts),
2478 Err(e) => {
2479 throw_exception(&mut env, &e);
2480 JObject::null()
2481 }
2482 }
2483}
2484
2485#[unsafe(no_mangle)]
2486pub extern "system" fn Java_com_stateset_embedded_GeneralLedger_nativeGetTrialBalance<'local>(
2487 mut env: JNIEnv<'local>,
2488 _class: JClass<'local>,
2489 ptr: jlong,
2490) -> JObject<'local> {
2491 let today = chrono::Utc::now().date_naive();
2493 let result = use_handle(ptr, |commerce| {
2494 commerce.general_ledger().get_trial_balance(today).map_err(|e| e.to_string())
2495 });
2496 match result {
2497 Ok(balance) => to_json_string(&env, &balance),
2498 Err(e) => {
2499 throw_exception(&mut env, &e);
2500 JObject::null()
2501 }
2502 }
2503}