seven365-zyprinter 1.0.9 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ios/Sources/Plugin/ZywellSDK.swift +144 -40
- package/package.json +1 -1
|
@@ -19,8 +19,8 @@ import ExternalAccessory
|
|
|
19
19
|
/// Common widths: 32 chars (58mm paper), 48 chars (80mm paper)
|
|
20
20
|
private let printerWidth: Int = 48
|
|
21
21
|
|
|
22
|
-
///
|
|
23
|
-
private let
|
|
22
|
+
/// Default separator character (can be overridden per-template)
|
|
23
|
+
private let defaultSeparatorChar: String = "-"
|
|
24
24
|
|
|
25
25
|
private var bleManager: POSBLEManager?
|
|
26
26
|
private var wifiManagers: [String: POSWIFIManager] = [:]
|
|
@@ -402,6 +402,9 @@ import ExternalAccessory
|
|
|
402
402
|
private func formatReceiptForPrinter(template: [String: Any]) -> Data? {
|
|
403
403
|
var printData = Data()
|
|
404
404
|
|
|
405
|
+
// Get separator character from template (dynamic) or use default
|
|
406
|
+
let separatorChar = getString(template["separator"]) ?? defaultSeparatorChar
|
|
407
|
+
|
|
405
408
|
// Initialize printer
|
|
406
409
|
printData.append(Data([0x1B, 0x40]))
|
|
407
410
|
|
|
@@ -460,23 +463,57 @@ import ExternalAccessory
|
|
|
460
463
|
}
|
|
461
464
|
}
|
|
462
465
|
|
|
463
|
-
// Left align (ESC a 0)
|
|
466
|
+
// Left align for separator (ESC a 0)
|
|
464
467
|
printData.append(Data([0x1B, 0x61, 0x00]))
|
|
465
468
|
|
|
466
469
|
// Separator (normal font size)
|
|
467
|
-
if let separatorData = generateSeparator().data(using: .utf8) {
|
|
470
|
+
if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
|
|
468
471
|
printData.append(separatorData)
|
|
469
472
|
}
|
|
470
473
|
|
|
471
474
|
// ========== ORDER INFO SECTION ==========
|
|
472
|
-
//
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
475
|
+
// Center align for order info (ESC a 1)
|
|
476
|
+
printData.append(Data([0x1B, 0x61, 0x01]))
|
|
477
|
+
|
|
478
|
+
// Template type (e.g., "Kitchen Tickets") - customizable formatting
|
|
479
|
+
if let orderType = getString(template["order_type"]) {
|
|
480
|
+
// Get order_type formatting from order_type_config object
|
|
481
|
+
var orderTypeSizeCode: UInt8 = 0x00 // Default to normal size
|
|
482
|
+
var orderTypeBold = false // Default to not bold
|
|
483
|
+
|
|
484
|
+
if let orderTypeConfig = template["order_type_config"] as? [String: Any] {
|
|
485
|
+
if let size = orderTypeConfig["size"] {
|
|
486
|
+
orderTypeSizeCode = mapHeaderSizeToCode(size)
|
|
487
|
+
}
|
|
488
|
+
if let bold = orderTypeConfig["bold"] as? Bool {
|
|
489
|
+
orderTypeBold = bold
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
// Apply order_type formatting
|
|
494
|
+
if orderTypeBold {
|
|
495
|
+
printData.append(Data([0x1B, 0x45, 0x01])) // Bold on
|
|
496
|
+
}
|
|
497
|
+
if orderTypeSizeCode != 0x00 {
|
|
498
|
+
printData.append(Data([0x1D, 0x21, orderTypeSizeCode])) // Set size
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// Print order type
|
|
502
|
+
if let orderTypeData = (orderType + "\n").data(using: .utf8) {
|
|
503
|
+
printData.append(orderTypeData)
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
// Reset order_type formatting
|
|
507
|
+
if orderTypeSizeCode != 0x00 {
|
|
508
|
+
printData.append(Data([0x1D, 0x21, 0x00])) // Normal size
|
|
509
|
+
}
|
|
510
|
+
if orderTypeBold {
|
|
511
|
+
printData.append(Data([0x1B, 0x45, 0x00])) // Bold off
|
|
512
|
+
}
|
|
476
513
|
}
|
|
477
514
|
|
|
478
515
|
// Table and order number - Read formatting from order_info or use defaults
|
|
479
|
-
var orderInfoSizeCode: UInt8 =
|
|
516
|
+
var orderInfoSizeCode: UInt8 = 0x11 // Default to 2x (large)
|
|
480
517
|
var orderInfoBold = true // Default to bold
|
|
481
518
|
|
|
482
519
|
if let orderInfo = template["order_info"] as? [String: Any] {
|
|
@@ -519,17 +556,18 @@ import ExternalAccessory
|
|
|
519
556
|
printData.append(Data([0x1B, 0x45, 0x00])) // Bold off
|
|
520
557
|
}
|
|
521
558
|
|
|
522
|
-
|
|
559
|
+
// Left align for items section (ESC a 0)
|
|
560
|
+
printData.append(Data([0x1B, 0x61, 0x00]))
|
|
523
561
|
|
|
524
562
|
// Separator for items section (normal font size)
|
|
525
|
-
if let separatorData = generateSeparator().data(using: .utf8) {
|
|
563
|
+
if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
|
|
526
564
|
printData.append(separatorData)
|
|
527
565
|
}
|
|
528
566
|
|
|
529
567
|
// ========== ITEMS SECTION (NEW STRUCTURE) ==========
|
|
530
568
|
if let kitchen = template["kitchen"] as? [[String: Any]] {
|
|
531
569
|
// Get item formatting from item object
|
|
532
|
-
var itemSizeCode: UInt8 =
|
|
570
|
+
var itemSizeCode: UInt8 = 0x11 // Default to 2x (large) for better readability
|
|
533
571
|
var itemBold = false
|
|
534
572
|
|
|
535
573
|
if let item = template["item"] as? [String: Any] {
|
|
@@ -545,14 +583,14 @@ import ExternalAccessory
|
|
|
545
583
|
if itemBold {
|
|
546
584
|
printData.append(Data([0x1B, 0x45, 0x01])) // Bold on
|
|
547
585
|
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
}
|
|
586
|
+
// Always send size command to ensure items are at configured size
|
|
587
|
+
printData.append(Data([0x1D, 0x21, itemSizeCode])) // Set size (even if 0x00 for normal)
|
|
551
588
|
|
|
552
589
|
// Get modifier formatting from modifier object
|
|
553
590
|
var modifierStyle = "bullet" // default
|
|
554
591
|
var modifierSizeCode: UInt8 = 0x00
|
|
555
592
|
var modifierIndent = " " // default: medium
|
|
593
|
+
var modifierBold = false // NEW: bold support for modifiers
|
|
556
594
|
|
|
557
595
|
if let modifier = template["modifier"] as? [String: Any] {
|
|
558
596
|
if let style = getString(modifier["style"]) {
|
|
@@ -569,6 +607,9 @@ import ExternalAccessory
|
|
|
569
607
|
default: modifierIndent = " "
|
|
570
608
|
}
|
|
571
609
|
}
|
|
610
|
+
if let bold = modifier["bold"] as? Bool {
|
|
611
|
+
modifierBold = bold
|
|
612
|
+
}
|
|
572
613
|
}
|
|
573
614
|
|
|
574
615
|
for item in kitchen {
|
|
@@ -598,25 +639,30 @@ import ExternalAccessory
|
|
|
598
639
|
|
|
599
640
|
// Print modifiers
|
|
600
641
|
if let modifiers = item["modifiers"] as? [[String: Any]] {
|
|
601
|
-
// Apply modifier size
|
|
642
|
+
// Apply modifier formatting (size and bold)
|
|
602
643
|
if modifierSizeCode != 0x00 {
|
|
603
644
|
printData.append(Data([0x1D, 0x21, modifierSizeCode]))
|
|
604
645
|
}
|
|
646
|
+
if modifierBold {
|
|
647
|
+
printData.append(Data([0x1B, 0x45, 0x01])) // Bold on
|
|
648
|
+
}
|
|
605
649
|
|
|
606
650
|
for mod in modifiers {
|
|
607
651
|
if let modName = getString(mod["name"]) {
|
|
608
652
|
var prefix = ""
|
|
609
653
|
|
|
610
654
|
// Determine prefix based on style
|
|
655
|
+
// Note: Using ASCII-compatible characters only
|
|
656
|
+
// Unicode characters like • and → display as garbled text on thermal printers
|
|
611
657
|
switch modifierStyle.lowercased() {
|
|
612
658
|
case "dash":
|
|
613
659
|
prefix = "-"
|
|
614
660
|
case "bullet":
|
|
615
|
-
prefix = "
|
|
661
|
+
prefix = "*" // ASCII asterisk instead of Unicode bullet
|
|
616
662
|
case "arrow":
|
|
617
|
-
prefix = "
|
|
663
|
+
prefix = ">" // ASCII greater-than instead of Unicode arrow
|
|
618
664
|
default:
|
|
619
|
-
prefix = "
|
|
665
|
+
prefix = "-" // Default to dash for best compatibility
|
|
620
666
|
}
|
|
621
667
|
|
|
622
668
|
// Build modifier line
|
|
@@ -628,17 +674,18 @@ import ExternalAccessory
|
|
|
628
674
|
}
|
|
629
675
|
}
|
|
630
676
|
|
|
631
|
-
// Reset modifier size
|
|
677
|
+
// Reset modifier formatting (size and bold)
|
|
678
|
+
if modifierBold {
|
|
679
|
+
printData.append(Data([0x1B, 0x45, 0x00])) // Bold off
|
|
680
|
+
}
|
|
632
681
|
if modifierSizeCode != 0x00 {
|
|
633
|
-
printData.append(Data([0x1D, 0x21,
|
|
682
|
+
printData.append(Data([0x1D, 0x21, itemSizeCode])) // Reset to item size, not 0x00
|
|
634
683
|
}
|
|
635
684
|
}
|
|
636
685
|
}
|
|
637
686
|
|
|
638
687
|
// Reset item formatting
|
|
639
|
-
|
|
640
|
-
printData.append(Data([0x1D, 0x21, 0x00])) // Normal size
|
|
641
|
-
}
|
|
688
|
+
printData.append(Data([0x1D, 0x21, 0x00])) // Always reset to normal size
|
|
642
689
|
if itemBold {
|
|
643
690
|
printData.append(Data([0x1B, 0x45, 0x00])) // Bold off
|
|
644
691
|
}
|
|
@@ -647,7 +694,7 @@ import ExternalAccessory
|
|
|
647
694
|
|
|
648
695
|
// ========== TOTAL SECTION ==========
|
|
649
696
|
// Separator before total (normal font size)
|
|
650
|
-
if let separatorData = generateSeparator().data(using: .utf8) {
|
|
697
|
+
if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
|
|
651
698
|
printData.append(separatorData)
|
|
652
699
|
}
|
|
653
700
|
|
|
@@ -675,7 +722,7 @@ import ExternalAccessory
|
|
|
675
722
|
// ========== TOTAL SECTION (NEW STRUCTURE) ==========
|
|
676
723
|
if let total = getString(template["total"]) {
|
|
677
724
|
// Separator (may need to account for total font size)
|
|
678
|
-
if let separatorData = generateSeparator().data(using: .utf8) {
|
|
725
|
+
if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
|
|
679
726
|
printData.append(separatorData)
|
|
680
727
|
}
|
|
681
728
|
|
|
@@ -713,19 +760,20 @@ import ExternalAccessory
|
|
|
713
760
|
}
|
|
714
761
|
}
|
|
715
762
|
|
|
716
|
-
//
|
|
717
|
-
if let
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
763
|
+
// Payment method (with separator only if payment method exists)
|
|
764
|
+
if let paymentMethod = getString(template["paymentMethod"]) {
|
|
765
|
+
// Separator before payment
|
|
766
|
+
if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
|
|
767
|
+
printData.append(separatorData)
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if let paymentData = ("PAYMENT BY:\(paymentMethod)\t\(getString(template["total"]) ?? "")\n").data(using: .utf8) {
|
|
771
|
+
printData.append(paymentData)
|
|
772
|
+
}
|
|
725
773
|
}
|
|
726
774
|
|
|
727
|
-
//
|
|
728
|
-
if let separatorData = generateSeparator().data(using: .utf8) {
|
|
775
|
+
// Single separator before footer
|
|
776
|
+
if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
|
|
729
777
|
printData.append(separatorData)
|
|
730
778
|
}
|
|
731
779
|
|
|
@@ -761,10 +809,21 @@ import ExternalAccessory
|
|
|
761
809
|
printData.append(messageData)
|
|
762
810
|
}
|
|
763
811
|
|
|
764
|
-
// Reset footer formatting
|
|
812
|
+
// Reset footer formatting before timestamp
|
|
765
813
|
if footerSizeCode != 0x00 {
|
|
766
814
|
printData.append(Data([0x1D, 0x21, 0x00])) // Normal size
|
|
767
815
|
}
|
|
816
|
+
if footerBold {
|
|
817
|
+
printData.append(Data([0x1B, 0x45, 0x00])) // Bold off
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
// Print timestamp
|
|
821
|
+
let dateFormat = getString(footer["date_format"]) ?? "YYYY-MM-DD"
|
|
822
|
+
let timeFormat = getString(footer["time_format"]) ?? "24H"
|
|
823
|
+
let timestamp = formatTimestamp(dateFormat: dateFormat, timeFormat: timeFormat)
|
|
824
|
+
if let timestampData = (timestamp + "\n").data(using: .utf8) {
|
|
825
|
+
printData.append(timestampData)
|
|
826
|
+
}
|
|
768
827
|
}
|
|
769
828
|
|
|
770
829
|
// Line feeds
|
|
@@ -834,6 +893,48 @@ import ExternalAccessory
|
|
|
834
893
|
return String(describing: value)
|
|
835
894
|
}
|
|
836
895
|
|
|
896
|
+
/**
|
|
897
|
+
* Formats the current timestamp based on date and time format preferences
|
|
898
|
+
* - Parameters:
|
|
899
|
+
* - dateFormat: Format string like "YYYY-MM-DD", "DD-MM-YYYY", "MM-DD-YYYY"
|
|
900
|
+
* - timeFormat: "12H" or "24H"
|
|
901
|
+
* - Returns: Formatted timestamp string
|
|
902
|
+
*/
|
|
903
|
+
private func formatTimestamp(dateFormat: String, timeFormat: String) -> String {
|
|
904
|
+
let now = Date()
|
|
905
|
+
let calendar = Calendar.current
|
|
906
|
+
|
|
907
|
+
let year = calendar.component(.year, from: now)
|
|
908
|
+
let month = calendar.component(.month, from: now)
|
|
909
|
+
let day = calendar.component(.day, from: now)
|
|
910
|
+
let hour = calendar.component(.hour, from: now)
|
|
911
|
+
let minute = calendar.component(.minute, from: now)
|
|
912
|
+
let second = calendar.component(.second, from: now)
|
|
913
|
+
|
|
914
|
+
// Format date
|
|
915
|
+
var formattedDate: String
|
|
916
|
+
switch dateFormat {
|
|
917
|
+
case "DD-MM-YYYY", "DD/MM/YYYY":
|
|
918
|
+
formattedDate = String(format: "%02d-%02d-%04d", day, month, year)
|
|
919
|
+
case "MM-DD-YYYY", "MM/DD/YYYY":
|
|
920
|
+
formattedDate = String(format: "%02d-%02d-%04d", month, day, year)
|
|
921
|
+
default: // "YYYY-MM-DD"
|
|
922
|
+
formattedDate = String(format: "%04d-%02d-%02d", year, month, day)
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
// Format time
|
|
926
|
+
var formattedTime: String
|
|
927
|
+
if timeFormat == "12H" {
|
|
928
|
+
let hour12 = hour % 12 == 0 ? 12 : hour % 12
|
|
929
|
+
let ampm = hour >= 12 ? "PM" : "AM"
|
|
930
|
+
formattedTime = String(format: "%d:%02d:%02d %@", hour12, minute, second, ampm)
|
|
931
|
+
} else { // 24H
|
|
932
|
+
formattedTime = String(format: "%02d:%02d:%02d", hour, minute, second)
|
|
933
|
+
}
|
|
934
|
+
|
|
935
|
+
return "\(formattedDate) \(formattedTime)"
|
|
936
|
+
}
|
|
937
|
+
|
|
837
938
|
/**
|
|
838
939
|
* Generates a separator line based on current printer width and font magnification
|
|
839
940
|
* - Parameter sizeCode: The current font size code (0x00, 0x11, 0x22, 0x33)
|
|
@@ -845,7 +946,7 @@ import ExternalAccessory
|
|
|
845
946
|
* - 0x22 (3x3): 3x width (one-third as many characters fit)
|
|
846
947
|
* - 0x33 (4x4): 4x width (one-quarter as many characters fit)
|
|
847
948
|
*/
|
|
848
|
-
private func generateSeparator(forSizeCode sizeCode: UInt8 = 0x00) -> String {
|
|
949
|
+
private func generateSeparator(forSizeCode sizeCode: UInt8 = 0x00, withChar separatorChar: String? = nil) -> String {
|
|
849
950
|
// Calculate width divisor based on font magnification
|
|
850
951
|
let widthMultiplier: Int
|
|
851
952
|
switch sizeCode {
|
|
@@ -858,8 +959,11 @@ import ExternalAccessory
|
|
|
858
959
|
// Calculate actual character count that fits on the line
|
|
859
960
|
let effectiveWidth = printerWidth / widthMultiplier
|
|
860
961
|
|
|
962
|
+
// Use provided separator character or fall back to default
|
|
963
|
+
let charToUse = separatorChar ?? defaultSeparatorChar
|
|
964
|
+
|
|
861
965
|
// Generate separator string
|
|
862
|
-
return String(repeating:
|
|
966
|
+
return String(repeating: charToUse, count: effectiveWidth) + "\n"
|
|
863
967
|
}
|
|
864
968
|
|
|
865
969
|
// MARK: - Callback Storage
|
package/package.json
CHANGED