Class: Extface::Driver::EltradeTmU220

Inherits:
Base::Fiscal
  • Object
show all
Includes:
Extface::Driver::Eltrade::CommandsFp4
Defined in:
app/models/extface/driver/eltrade_tm_u220.rb

Defined Under Namespace

Classes: Frame, PrinterStatus

Constant Summary collapse

NAME =
'Eltrade TM-U220 (Serial)'.freeze
RESPONSE_TIMEOUT =

seconds

3
INVALID_FRAME_RETRIES =

count

6
BUSY_MAX_WAIT_CYCLES =

count

60
BAD_SEQ_MAX_COUNT =
3
FLAG_TRUE =
"\xff\xff"
FLAG_FALSE =
"\x00\x00"

Instance Method Summary collapse

Instance Method Details

#add_comment(text) ⇒ Object



143
144
145
146
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 143

def add_comment(text)
  raise "Not in fiscal session" unless @fiscal_session
  send_comment text
end

#add_payment(value = nil, type_num = nil) ⇒ Object

0, 1, 2, 3



148
149
150
151
152
153
154
155
156
157
158
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 148

def add_payment(value = nil, type_num = nil) # 0, 1, 2, 3
  raise "Not in fiscal session" unless @fiscal_session
  value_bytes = "\x00\x00\x00\x00" # recalculate
  unless value.nil?
    value_units = (value * 100).to_i # !FIXME
    value_bytes = "".b
    4.times{ |shift| value_bytes.insert 0, ((value_units >> shift*8) & 0xff).chr }
  end
  fsend Receipt::PRINT_RECEIPT, "" << (9 + (type_num || 0)).chr << value_bytes
  status = get_printer_status
end

#add_sale(sale_item) ⇒ Object



137
138
139
140
141
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 137

def add_sale(sale_item)
  raise "Not in fiscal session" unless @fiscal_session
  send_plu build_sale_data(sale_item)
  add_comment(sale_item.text2) if sale_item.text2.present?
end

#build_packet(cmd, data = "") ⇒ Object



211
212
213
214
215
216
217
218
219
220
221
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 211

def build_packet(cmd, data = "")
  "".tap() do |packet|
    packet << STRT.b
    packet << 0x00 #address
    packet << sequence_number
    packet << cmd
    packet << data.length
    packet << data.b
    packet << check_sum(packet[2..-1])
  end
end

#cancel_doc_sessionObject



96
97
98
99
100
101
102
103
104
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 96

def cancel_doc_session
  device.session("Doc cancel") do |s|
    s.notify "Doc Cancel Start"
    # cancel old one by open/close new one
    s.open_fiscal_doc
    s.close_fiscal_doc
    s.notify "Doc Cancel End"
  end
end

#check_statusObject



202
203
204
205
206
207
208
209
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 202

def check_status
  flush
  status = get_printer_status
  #TODO check for:
  #1. sold PLUs dangerously high -> solution PLU Report (0x32)
  #2. open bon and transaction count
  errors.empty?
end

#close_fiscal_docObject



131
132
133
134
135
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 131

def close_fiscal_doc
  raise "Not in fiscal session" unless @fiscal_session
  close_receipt
  @fiscal_session = false
end

#close_non_fiscal_docObject



117
118
119
120
121
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 117

def close_non_fiscal_doc
  raise "Not in print session" unless @print_session
  close_receipt
  @print_session = false
end

#fiscal_testObject



53
54
55
56
57
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 53

def fiscal_test
  sale_and_pay_items_session([
    SaleItem.new( price: 0.01, text1: "Extface Test" )
  ])
end

#frecv(timeout) ⇒ Object

return RespFrame or nil



263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 263

def frecv(timeout) # return RespFrame or nil
  rframe = nil
  BAD_SEQ_MAX_COUNT.times do
    if frame_bytes = pull(timeout)
      rframe = Frame.new(frame_bytes.b)
      if rframe.seq.ord == sequence_number(false) #accept only current sequence number as reply
        break
      else
        errors.add :base, "Sequence mismatch"
        rframe = nil #invalidate mismatch sequence frame for the last retry
      end
    else
      errors.add :base, "No data received from device"
      break
    end
  end
  return rframe
end

#fsend(cmd, data = "") ⇒ Object

return data or nil



223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 223

def fsend(cmd, data = "") #return data or nil
  result = false
  status_invalid_responses = 0
  BUSY_MAX_WAIT_CYCLES.times do |retries|
    errors.clear
    push build_packet(Info::GET_STATUS)
    if stat_frame = frecv(RESPONSE_TIMEOUT)
      if stat_frame.valid?
        break if stat_frame.ready?
      else
        status_invalid_responses += 1
        if status_invalid_responses > INVALID_FRAME_RETRIES
          errors.add :base, "#{INVALID_FRAME_RETRIES} Broken Packets Received. Abort!"
          break
        end
      end
    end
    errors.add :base, "#{BUSY_MAX_WAIT_CYCLES} Busy Packets Received. Abort!"
  end
  return(result) if errors.any?
  
  packet_data = build_packet(cmd, data)
  INVALID_FRAME_RETRIES.times do |retries|
    errors.clear
    push packet_data
    if resp = frecv(RESPONSE_TIMEOUT)
      if resp.valid?
        result = resp.data
        break
      else
        resp.errors.full_messages.each do |msg|
          errors.add :base, msg
        end
      end
    end
    errors.add :base, "#{INVALID_FRAME_RETRIES} Broken Packets Received. Abort!"
  end
  return result
end

#get_printer_statusObject



198
199
200
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 198

def get_printer_status
  PrinterStatus.new(fsend(Info::GET_PRINTER_STATUS))
end

#handle(buffer) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 23

def handle(buffer)
  bytes_processed = 0
  if frame_match = buffer.match(/\xAA\x55.{3}(.{1}).*/nm) #m Treat \x0a as a character matched by .
    len = frame_match.captures.first.ord
    skip = frame_match.pre_match.length
    bytes_processed = skip + 7 + len # 6 pre + 1 check sum
    if bytes_processed <= buffer.length #packet in buffer
      rpush buffer[skip..bytes_processed]
    else
      bytes_processed = skip #not whole packet, just remove trail
    end
  end
  return bytes_processed
end

#non_fiscal_testObject

tests



39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 39

def non_fiscal_test
  device.session("Non Fiscal Text") do |s|
    s.notify "Printing Non Fiscal Text"
    s.open_non_fiscal_doc
    s.print "********************************"
    s.print "Extface Print Test".center(32)
    s.print "********************************"
    s.print ""
    s.print "Driver: " + "#{self.class::NAME}".truncate(24)
    s.close_non_fiscal_doc
    s.notify "Printing finished"
  end
end

#open_fiscal_doc(operator = '', password = '') ⇒ Object

fiscal



125
126
127
128
129
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 125

def open_fiscal_doc(operator = '', password = '')
  set_operatior(operator) if operator.present?
  open_receipt
  @fiscal_session = true
end

#open_non_fiscal_docObject

print



107
108
109
110
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 107

def open_non_fiscal_doc
  open_receipt Receipt::Variant::START_COMMENT_RECEIPT
  @print_session = true
end

#payed_recv_account(value = 0.00, payment_type_num = 0) ⇒ Object



165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 165

def (value = 0.00, payment_type_num = 0)
  raise "Incorrect Amount Value" if value.zero?
  value_bytes = "\x00\x00\x00\x00" # recalculate
  unless value.nil?
    value_units = 0x100000000 + (value * 100).to_i # !FIXME
    value_bytes = "".b
    4.times{ |shift| value_bytes.insert 0, ((value_units >> shift*8) & 0xff).chr }
  end
  device.session("Payed Out / Received on Account (#{value.to_s})") do |s|
    s.notify "Payed / Received Start"
    fsend Other::PAYED_RECV_ACCOUNT, "" << (1 + payment_type_num).chr << value_bytes
    status = get_printer_status
    s.notify "Payed / Received End"
  end
end

#pbcd(byte) ⇒ Object



282
283
284
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 282

def pbcd(byte)
  ((byte / 10) << 4) | (byte % 10)
end

#period_report_session(from, to, detailed = true) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 78

def period_report_session(from, to, detailed = true)
  device.session("FP Report #{from.to_date.human} - #{to.to_date.human} (#{ detailed ? 'detailed' : 'short' })") do |s|
    dates_bytes = "".b
    dates_bytes << pbcd(from.day)
    dates_bytes << pbcd(from.month)
    dates_bytes << pbcd(from.year - 2000)
    dates_bytes << 0
    dates_bytes << pbcd(to.day)
    dates_bytes << pbcd(to.month)
    dates_bytes << pbcd(to.year - 2000)
    dates_bytes << 0
    s.notify "FP Report Start"
    s.fsend detailed ? Reports::FP_DETAILED_DATES : Reports::FP_GENERAL_DATES, dates_bytes
    status = s.get_printer_status
    s.notify "FP Report End"
  end
end


112
113
114
115
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 112

def print(text)
  raise "Not in print session" unless @print_session
  send_comment text
end

#sale_and_pay_items_session(items = [], operator = '', password = '') ⇒ Object

basket



182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 182

def sale_and_pay_items_session(items = [], operator = '', password = '')
  device.session("Fiscal Doc") do |s|
    s.notify "Open Fiscal Receipt"
    s.open_fiscal_doc operator, password
    s.notify "Register Sale"
    items.each do |item|
      s.add_sale(item)
    end
    s.notify "Register Payment"
    s.total_payment
    s.notify "Close Fiscal Receipt"
    s.close_fiscal_doc
    s.notify "Fiscalization Completed!"
  end
end

#total_paymentObject



160
161
162
163
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 160

def total_payment
  raise "Not in fiscal session" unless @fiscal_session
  add_payment
end

#x_report_sessionObject



69
70
71
72
73
74
75
76
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 69

def x_report_session
  device.session("X Report") do |s|
    s.notify "X Report Start"
    s.fsend Reports::DAILY_REPORT, FLAG_FALSE
    status = s.get_printer_status
    s.notify "X Report End"
  end
end

#z_report_sessionObject

reports



60
61
62
63
64
65
66
67
# File 'app/models/extface/driver/eltrade_tm_u220.rb', line 60

def z_report_session
  device.session("Z Report") do |s|
    s.notify "Z Report Start"
    s.fsend Reports::DAILY_REPORT, FLAG_TRUE
    status = s.get_printer_status
    s.notify "Z Report End"
  end
end