seven365-zyprinter 1.0.8 → 1.0.10

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.
@@ -13,6 +13,15 @@ import ExternalAccessory
13
13
 
14
14
  @objc public class ZywellSDK: NSObject {
15
15
 
16
+ // MARK: - Printer Configuration
17
+
18
+ /// Default printer width in characters (for 80mm thermal paper)
19
+ /// Common widths: 32 chars (58mm paper), 48 chars (80mm paper)
20
+ private let printerWidth: Int = 48
21
+
22
+ /// Default separator character (can be overridden per-template)
23
+ private let defaultSeparatorChar: String = "-"
24
+
16
25
  private var bleManager: POSBLEManager?
17
26
  private var wifiManagers: [String: POSWIFIManager] = [:]
18
27
  private var discoveredPeripherals: [CBPeripheral] = []
@@ -393,6 +402,9 @@ import ExternalAccessory
393
402
  private func formatReceiptForPrinter(template: [String: Any]) -> Data? {
394
403
  var printData = Data()
395
404
 
405
+ // Get separator character from template (dynamic) or use default
406
+ let separatorChar = getString(template["separator"]) ?? defaultSeparatorChar
407
+
396
408
  // Initialize printer
397
409
  printData.append(Data([0x1B, 0x40]))
398
410
 
@@ -451,22 +463,45 @@ import ExternalAccessory
451
463
  }
452
464
  }
453
465
 
454
- // Left align (ESC a 0)
466
+ // Left align for separator (ESC a 0)
455
467
  printData.append(Data([0x1B, 0x61, 0x00]))
456
468
 
457
- // Separator
458
- if let separatorData = ("--------------------------------\n").data(using: .utf8) {
469
+ // Separator (normal font size)
470
+ if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
459
471
  printData.append(separatorData)
460
472
  }
461
473
 
462
474
  // ========== ORDER INFO SECTION ==========
463
- // Template type (e.g., "Kitchen Tickets")
475
+ // Center align for order info (ESC a 1)
476
+ printData.append(Data([0x1B, 0x61, 0x01]))
477
+
478
+ // Template type (e.g., "Kitchen Tickets") - normal size
464
479
  if let orderType = getString(template["order_type"]),
465
480
  let orderTypeData = (orderType + "\n").data(using: .utf8) {
466
481
  printData.append(orderTypeData)
467
482
  }
468
483
 
469
- // Table and order number with prefix
484
+ // Table and order number - Read formatting from order_info or use defaults
485
+ var orderInfoSizeCode: UInt8 = 0x11 // Default to 2x (large)
486
+ var orderInfoBold = true // Default to bold
487
+
488
+ if let orderInfo = template["order_info"] as? [String: Any] {
489
+ if let size = orderInfo["size"] {
490
+ orderInfoSizeCode = mapHeaderSizeToCode(size)
491
+ }
492
+ if let bold = orderInfo["bold"] as? Bool {
493
+ orderInfoBold = bold
494
+ }
495
+ }
496
+
497
+ // Apply order info formatting
498
+ if orderInfoBold {
499
+ printData.append(Data([0x1B, 0x45, 0x01])) // Bold on
500
+ }
501
+ if orderInfoSizeCode != 0x00 {
502
+ printData.append(Data([0x1D, 0x21, orderInfoSizeCode])) // Set size from config
503
+ }
504
+
470
505
  var orderInfoLine = ""
471
506
  if let tableName = getString(template["table_name"]) {
472
507
  orderInfoLine += tableName
@@ -482,16 +517,26 @@ import ExternalAccessory
482
517
  printData.append(orderInfoData)
483
518
  }
484
519
 
520
+ // Reset formatting back to normal
521
+ if orderInfoSizeCode != 0x00 {
522
+ printData.append(Data([0x1D, 0x21, 0x00])) // Normal size
523
+ }
524
+ if orderInfoBold {
525
+ printData.append(Data([0x1B, 0x45, 0x00])) // Bold off
526
+ }
485
527
 
486
- // Separator for items section
487
- if let separatorData = ("--------------------------------\n").data(using: .utf8) {
528
+ // Left align for items section (ESC a 0)
529
+ printData.append(Data([0x1B, 0x61, 0x00]))
530
+
531
+ // Separator for items section (normal font size)
532
+ if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
488
533
  printData.append(separatorData)
489
534
  }
490
535
 
491
536
  // ========== ITEMS SECTION (NEW STRUCTURE) ==========
492
537
  if let kitchen = template["kitchen"] as? [[String: Any]] {
493
538
  // Get item formatting from item object
494
- var itemSizeCode: UInt8 = 0x00
539
+ var itemSizeCode: UInt8 = 0x11 // Default to 2x (large) for better readability
495
540
  var itemBold = false
496
541
 
497
542
  if let item = template["item"] as? [String: Any] {
@@ -608,8 +653,8 @@ import ExternalAccessory
608
653
  }
609
654
 
610
655
  // ========== TOTAL SECTION ==========
611
- // Separator before total
612
- if let separatorData = ("--------------------------------\n").data(using: .utf8) {
656
+ // Separator before total (normal font size)
657
+ if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
613
658
  printData.append(separatorData)
614
659
  }
615
660
 
@@ -636,8 +681,8 @@ import ExternalAccessory
636
681
 
637
682
  // ========== TOTAL SECTION (NEW STRUCTURE) ==========
638
683
  if let total = getString(template["total"]) {
639
- // Separator
640
- if let separatorData = ("--------------------------------\n").data(using: .utf8) {
684
+ // Separator (may need to account for total font size)
685
+ if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
641
686
  printData.append(separatorData)
642
687
  }
643
688
 
@@ -675,8 +720,8 @@ import ExternalAccessory
675
720
  }
676
721
  }
677
722
 
678
- // Separator
679
- if let separatorData = ("--------------------------------\n").data(using: .utf8) {
723
+ // Separator (normal font size)
724
+ if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
680
725
  printData.append(separatorData)
681
726
  }
682
727
 
@@ -686,8 +731,8 @@ import ExternalAccessory
686
731
  printData.append(paymentData)
687
732
  }
688
733
 
689
- // Separator
690
- if let separatorData = ("--------------------------------\n").data(using: .utf8) {
734
+ // Separator (normal font size)
735
+ if let separatorData = generateSeparator(withChar: separatorChar).data(using: .utf8) {
691
736
  printData.append(separatorData)
692
737
  }
693
738
 
@@ -723,10 +768,21 @@ import ExternalAccessory
723
768
  printData.append(messageData)
724
769
  }
725
770
 
726
- // Reset footer formatting
771
+ // Reset footer formatting before timestamp
727
772
  if footerSizeCode != 0x00 {
728
773
  printData.append(Data([0x1D, 0x21, 0x00])) // Normal size
729
774
  }
775
+ if footerBold {
776
+ printData.append(Data([0x1B, 0x45, 0x00])) // Bold off
777
+ }
778
+
779
+ // Print timestamp
780
+ let dateFormat = getString(footer["date_format"]) ?? "YYYY-MM-DD"
781
+ let timeFormat = getString(footer["time_format"]) ?? "24H"
782
+ let timestamp = formatTimestamp(dateFormat: dateFormat, timeFormat: timeFormat)
783
+ if let timestampData = (timestamp + "\n").data(using: .utf8) {
784
+ printData.append(timestampData)
785
+ }
730
786
  }
731
787
 
732
788
  // Line feeds
@@ -741,32 +797,40 @@ import ExternalAccessory
741
797
  // MARK: - Helper Functions
742
798
 
743
799
  private func mapHeaderSizeToCode(_ size: Any) -> UInt8 {
800
+ var resultCode: UInt8 = 0x00
801
+
744
802
  if let sizeInt = size as? Int {
745
803
  switch sizeInt {
746
- case 1: return 0x00
747
- case 2: return 0x11
748
- case 3: return 0x22
749
- case 4: return 0x33
750
- default: return 0x00
804
+ case 1: resultCode = 0x00
805
+ case 2: resultCode = 0x11
806
+ case 3: resultCode = 0x22
807
+ case 4: resultCode = 0x33
808
+ default: resultCode = 0x00
751
809
  }
810
+ print("ZywellSDK: Mapped size Int(\(sizeInt)) → 0x\(String(format: "%02X", resultCode))")
752
811
  } else if let sizeStr = size as? String {
753
812
  switch sizeStr.lowercased() {
754
- case "normal", "1": return 0x00
755
- case "large", "2": return 0x11
756
- case "xlarge", "3": return 0x22
757
- case "4": return 0x33
758
- default: return 0x00
813
+ case "normal", "1": resultCode = 0x00
814
+ case "large", "2": resultCode = 0x11
815
+ case "xlarge", "3": resultCode = 0x22
816
+ case "4": resultCode = 0x33
817
+ default: resultCode = 0x00
759
818
  }
819
+ print("ZywellSDK: Mapped size String(\"\(sizeStr)\") → 0x\(String(format: "%02X", resultCode))")
760
820
  } else if let sizeNum = size as? NSNumber {
761
821
  switch sizeNum.intValue {
762
- case 1: return 0x00
763
- case 2: return 0x11
764
- case 3: return 0x22
765
- case 4: return 0x33
766
- default: return 0x00
822
+ case 1: resultCode = 0x00
823
+ case 2: resultCode = 0x11
824
+ case 3: resultCode = 0x22
825
+ case 4: resultCode = 0x33
826
+ default: resultCode = 0x00
767
827
  }
828
+ print("ZywellSDK: Mapped size NSNumber(\(sizeNum.intValue)) → 0x\(String(format: "%02X", resultCode))")
829
+ } else {
830
+ print("ZywellSDK: Unknown size type: \(type(of: size)), defaulting to 0x00")
768
831
  }
769
- return 0x00
832
+
833
+ return resultCode
770
834
  }
771
835
 
772
836
  private func getBool(_ value: Any?) -> Bool {
@@ -788,6 +852,79 @@ import ExternalAccessory
788
852
  return String(describing: value)
789
853
  }
790
854
 
855
+ /**
856
+ * Formats the current timestamp based on date and time format preferences
857
+ * - Parameters:
858
+ * - dateFormat: Format string like "YYYY-MM-DD", "DD-MM-YYYY", "MM-DD-YYYY"
859
+ * - timeFormat: "12H" or "24H"
860
+ * - Returns: Formatted timestamp string
861
+ */
862
+ private func formatTimestamp(dateFormat: String, timeFormat: String) -> String {
863
+ let now = Date()
864
+ let calendar = Calendar.current
865
+
866
+ let year = calendar.component(.year, from: now)
867
+ let month = calendar.component(.month, from: now)
868
+ let day = calendar.component(.day, from: now)
869
+ let hour = calendar.component(.hour, from: now)
870
+ let minute = calendar.component(.minute, from: now)
871
+ let second = calendar.component(.second, from: now)
872
+
873
+ // Format date
874
+ var formattedDate: String
875
+ switch dateFormat {
876
+ case "DD-MM-YYYY", "DD/MM/YYYY":
877
+ formattedDate = String(format: "%02d-%02d-%04d", day, month, year)
878
+ case "MM-DD-YYYY", "MM/DD/YYYY":
879
+ formattedDate = String(format: "%02d-%02d-%04d", month, day, year)
880
+ default: // "YYYY-MM-DD"
881
+ formattedDate = String(format: "%04d-%02d-%02d", year, month, day)
882
+ }
883
+
884
+ // Format time
885
+ var formattedTime: String
886
+ if timeFormat == "12H" {
887
+ let hour12 = hour % 12 == 0 ? 12 : hour % 12
888
+ let ampm = hour >= 12 ? "PM" : "AM"
889
+ formattedTime = String(format: "%d:%02d:%02d %@", hour12, minute, second, ampm)
890
+ } else { // 24H
891
+ formattedTime = String(format: "%02d:%02d:%02d", hour, minute, second)
892
+ }
893
+
894
+ return "\(formattedDate) \(formattedTime)"
895
+ }
896
+
897
+ /**
898
+ * Generates a separator line based on current printer width and font magnification
899
+ * - Parameter sizeCode: The current font size code (0x00, 0x11, 0x22, 0x33)
900
+ * - Returns: A separator string with appropriate width
901
+ *
902
+ * Font magnification affects character width:
903
+ * - 0x00 (normal): 1x width
904
+ * - 0x11 (2x2): 2x width (half as many characters fit)
905
+ * - 0x22 (3x3): 3x width (one-third as many characters fit)
906
+ * - 0x33 (4x4): 4x width (one-quarter as many characters fit)
907
+ */
908
+ private func generateSeparator(forSizeCode sizeCode: UInt8 = 0x00, withChar separatorChar: String? = nil) -> String {
909
+ // Calculate width divisor based on font magnification
910
+ let widthMultiplier: Int
911
+ switch sizeCode {
912
+ case 0x11: widthMultiplier = 2 // 2x width
913
+ case 0x22: widthMultiplier = 3 // 3x width
914
+ case 0x33: widthMultiplier = 4 // 4x width
915
+ default: widthMultiplier = 1 // Normal width
916
+ }
917
+
918
+ // Calculate actual character count that fits on the line
919
+ let effectiveWidth = printerWidth / widthMultiplier
920
+
921
+ // Use provided separator character or fall back to default
922
+ let charToUse = separatorChar ?? defaultSeparatorChar
923
+
924
+ // Generate separator string
925
+ return String(repeating: charToUse, count: effectiveWidth) + "\n"
926
+ }
927
+
791
928
  // MARK: - Callback Storage
792
929
 
793
930
  private var discoveryCompletion: (([[String: Any]], String?) -> Void)?
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "seven365-zyprinter",
3
- "version": "1.0.8",
3
+ "version": "1.0.10",
4
4
  "description": "Capacitor plugin for Zywell/Zyprint thermal printer integration with Bluetooth and WiFi support",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",