Class: Extface::Driver::DaisyFx1200

Inherits:
Base::Fiscal
  • Object
show all
Includes:
Extface::Driver::Daisy::CommandsFx1200
Defined in:
app/models/extface/driver/daisy_fx1200.rb

Defined Under Namespace

Classes: RespFrame

Constant Summary collapse

NAME =
'Daisy FX1200 (Serial)'.freeze
RESPONSE_TIMEOUT =

seconds

3
INVALID_FRAME_RETRIES =

count (bad length, bad checksum)

6
ACKS_MAX_WAIT =

count / nothing is forever

60
NAKS_MAX_COUNT =

count

3
BAD_SEQ_MAX_COUNT =
3
NO_RESP_MAX_COUNT =
3
TAX_GROUPS_MAP =
{
  1 => "\xc0",
  2 => "\xc1",
  3 => "\xc2",
  4 => "\xc3",
  5 => "\xc4",
  6 => "\xc5",
  7 => "\xc6",
  8 => "\xc7"
}
PAYMENT_TYPE_MAP =
{
  1 => "P",
  2 => "N",
  3 => "C",
  4 => "D",
  5 => "B"
}

Instance Method Summary collapse

Instance Method Details

#add_comment(text) ⇒ Object



133
134
135
# File 'app/models/extface/driver/daisy_fx1200.rb', line 133

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

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



137
138
139
140
141
142
143
144
145
146
# File 'app/models/extface/driver/daisy_fx1200.rb', line 137

def add_payment(value = nil, type_num = nil)
  raise "Not in fiscal session" unless @fiscal_session
  payment_data = "".tap() do |data|
                        data << "\t"
                        data << PAYMENT_TYPE_MAP[type_num || 1] #by documentation this data can be ommitted, but got vrong value error
                        data << ("%.2f" % value) unless value.blank?
                      end
  p "PPPPPPPPPPPPPP payment_data: #{payment_data}"
  fsend(Sales::TOTAL, payment_data)
end

#add_sale(sale_item) ⇒ Object



128
129
130
131
# File 'app/models/extface/driver/daisy_fx1200.rb', line 128

def add_sale(sale_item)
  raise "Not in fiscal session" unless @fiscal_session
  fsend Sales::SALE_AND_SHOW, build_sale_data(sale_item)
end

#autocut(partial = true) ⇒ Object

other



199
200
201
202
# File 'app/models/extface/driver/daisy_fx1200.rb', line 199

def autocut(partial = true) # return "P" - success, "F" - failed
  resp = fsend(Printer::CUT)
  resp == "P"
end

#autofix_unclosed_docObject



189
190
191
192
193
194
195
196
# File 'app/models/extface/driver/daisy_fx1200.rb', line 189

def autofix_unclosed_doc
  if @last_fp_status
    unless (@last_fp_status[2].ord & 0x20).zero? and (@last_fp_status[2].ord & 0x08).zero?
      fsend Sales::CANCEL_DOC
      autocut
    end
  end
end

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



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

def build_packet(cmd, data = "")
  String.new.tap() do |packet|
    packet << STX
    packet << 0x20 + 4 + data.length
    packet << sequence_number
    packet << cmd
    packet << data
    packet << PA1
    packet << bcc(packet[1..-1])
    packet << ETX
  end
end

#cancel_doc_sessionObject



180
181
182
183
184
185
186
187
# File 'app/models/extface/driver/daisy_fx1200.rb', line 180

def cancel_doc_session
  device.session("Doc cancel") do |s|
    s.notify "Doc Cancel Start"
    s.fsend Sales::CANCEL_DOC
    s.autocut
    s.notify "Doc Cancel End"
  end
end

#check_statusObject

auto called for session, return true for OK



205
206
207
208
209
# File 'app/models/extface/driver/daisy_fx1200.rb', line 205

def check_status
  flush
  fsend(Info::STATUS) # return 6 byte status
  errors.empty?
end

#close_fiscal_docObject



122
123
124
125
126
# File 'app/models/extface/driver/daisy_fx1200.rb', line 122

def close_fiscal_doc
  raise "Not in fiscal session" unless @fiscal_session
  fsend Sales::END_FISCAL_DOC
  @fiscal_session = false
end

#close_non_fiscal_docObject



111
112
113
114
# File 'app/models/extface/driver/daisy_fx1200.rb', line 111

def close_non_fiscal_doc
  fsend Sales::END_NON_FISCAL_DOC
  @print_session = false
end

#fiscal_testObject



69
70
71
72
73
# File 'app/models/extface/driver/daisy_fx1200.rb', line 69

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

#frecv(timeout) ⇒ Object

return RespFrame or nil



274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
# File 'app/models/extface/driver/daisy_fx1200.rb', line 274

def frecv(timeout) # return RespFrame or nil
  rframe = nil
  BAD_SEQ_MAX_COUNT.times do
    errors.clear
    if frame_bytes = pull(timeout)
      rframe = RespFrame.new(frame_bytes.b)
      if rframe.seq.nil? || rframe.seq.ord == sequence_number(false) #accept only current sequence number as reply
        break
      else
        errors.add :base, "Sequence mismatch"
        p "Invalid sequence (expected: #{sequence_number(false).to_s(16)}, got: #{rframe.seq.ord.to_s(16)})"
        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



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
262
263
264
265
266
267
268
269
270
271
272
# File 'app/models/extface/driver/daisy_fx1200.rb', line 224

def fsend(cmd, data = "") #return data or nil
  packet_data = build_packet(cmd, data)
  result = false
  invalid_frames = 0
  nak_messages = 0
  no_resp = 0
  flush # fix mysterious double packet response, #TODO send 2 commands and then read 2 responses may fail
  push packet_data
  ACKS_MAX_WAIT.times do |retries|
    errors.clear
    @last_fp_status = nil
    if resp = frecv(RESPONSE_TIMEOUT)
      if resp.valid?
        @last_fp_status = resp.status
        human_status_errors(resp.status)
        if errors.empty?
          result = resp.data
          break
        else
          raise errors.full_messages.join(',')
        end
      else #ack, nak or bad
        if resp.nak?
          nak_messages += 1
          if nak_messages > NAKS_MAX_COUNT
            errors.add :base, "#{NAKS_MAX_COUNT} NAKs Received. Abort!"
            break
          end
        elsif !resp.ack?
          invalid_frames += 1
          if invalid_frames > INVALID_FRAME_RETRIES
            errors.add :base, "#{INVALID_FRAME_RETRIES} Broken Packets Received. Abort!"
            break
          end
        end
        push packet_data unless resp.ack?
      end
    else
      no_resp += 1
      if no_resp > NO_RESP_MAX_COUNT
        p "No reply in #{NO_RESP_MAX_COUNT * RESPONSE_TIMEOUT} seconds. Abort!"
        errors.add :base, "No reply in #{NO_RESP_MAX_COUNT * RESPONSE_TIMEOUT} seconds. Abort!"
        return result
      end
    end
    errors.add :base, "#{ACKS_MAX_WAIT} ACKs Received. Abort!"
  end
  return result
end

#handle(buffer) ⇒ Object

buffer is filled with multiple pushes, wait for full frame (ACKs)STX..PA2..PA1..ETX



47
48
49
50
51
52
# File 'app/models/extface/driver/daisy_fx1200.rb', line 47

def handle(buffer) #buffer is filled with multiple pushes, wait for full frame (ACKs)STX..PA2..PA1..ETX
  if i = buffer.index("\x03") || buffer.index("\x16") || buffer.index("\x15")
    rpush buffer[0..i]
    return i + 1 # return number of bytes processed
  end
end

#non_fiscal_testObject

tests



55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'app/models/extface/driver/daisy_fx1200.rb', line 55

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.fsend Printer::MOVE, "1"
    s.print "Driver: " + "#{self.class::NAME}".truncate(24)
    s.close_non_fiscal_doc
    s.notify "Printing finished"
  end
end

#open_fiscal_doc(operator = "1", password = "1") ⇒ Object

fiscal



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

def open_fiscal_doc(operator = "1", password = "1")
  fsend Sales::START_FISCAL_DOC, "#{operator.presence || "1"},#{password.presence || "1"},00001"
  @fiscal_session = true
end

#open_non_fiscal_docObject

print



101
102
103
104
# File 'app/models/extface/driver/daisy_fx1200.rb', line 101

def open_non_fiscal_doc
  fsend Sales::START_NON_FISCAL_DOC
  @print_session = true
end

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



153
154
155
156
157
158
159
160
161
# File 'app/models/extface/driver/daisy_fx1200.rb', line 153

def (value = 0.00, payment_type_num = 0)
  raise "Incorrect Amount Value" if value.zero?
  device.session("Payed Out / Received on Account (#{value.to_s})") do |s|
    s.notify "Payed / Received Start"
    fsend Other::ADD_SUB_SUMS, "" << ("%.2f" % value)
    status = get_printer_status
    s.notify "Payed / Received End"
  end
end

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



92
93
94
95
96
97
98
# File 'app/models/extface/driver/daisy_fx1200.rb', line 92

def period_report_session(from, to, detailed = true)
  device.session("Period Report #{ '(detailed)' if detailed }") do |s|
    s.notify "Period Report Start #{ '(detailed)' if detailed }"
    s.fsend detailed ? Reports::REPORT_FP_BY_DATE : Reports::COMPACT_REPORT_FP_BY_DATE, "#{from.strftime('%d%m%y')},#{to.strftime('%d%m%y')}"
    s.notify "Period Report End"
  end
end


106
107
108
109
# File 'app/models/extface/driver/daisy_fx1200.rb', line 106

def print(text)
  raise "Not in print session" unless @print_session
  fsend Sales::PRINT_NON_FISCAL_TEXT, text
end

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

basket



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

def sale_and_pay_items_session(items = [], operator = "1", password = "1")
  device.session("Fiscal Doc") do |s|
    s.notify "Fiscal Doc Start"
    s.open_fiscal_doc
    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 "Fiscal Doc End"
  end
end

#total_paymentObject



148
149
150
151
# File 'app/models/extface/driver/daisy_fx1200.rb', line 148

def total_payment
  raise "Not in fiscal session" unless @fiscal_session
  fsend(Sales::TOTAL, "\t")
end

#x_report_sessionObject



84
85
86
87
88
89
90
# File 'app/models/extface/driver/daisy_fx1200.rb', line 84

def x_report_session
  device.session("X Report") do |s|
    s.notify "X Report Start"
    s.fsend Closure::DAY_FIN_REPORT, "2"
    s.notify "X Report End"
  end
end

#z_report_sessionObject

reports



76
77
78
79
80
81
82
# File 'app/models/extface/driver/daisy_fx1200.rb', line 76

def z_report_session
  device.session("Z Report") do |s|
    s.notify "Z Report Start"
    s.fsend Closure::DAY_FIN_REPORT, "0"
    s.notify "Z Report End"
  end
end