japan_shipping_csv 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 66ce156620a2ec645fbe902b2f3b4ff3a8974001bd75ec3696b3032f7358b3e5
4
+ data.tar.gz: 76c6d23380f8fe1a7686b6d78d9855ff58211a83a1f56f6dd9e6d07bf1281f61
5
+ SHA512:
6
+ metadata.gz: 5949bb6efe276ca240a70c3e53f01e0f7b8f05368032a4dcdfe1ac67ae0a0da650f9cdae62606da9c3706d9e40a36dbac6f31de07e8b227d951a3957a8055467
7
+ data.tar.gz: 358964b07ab3741ddb52a5964e0579d409a4db03f33dbb517941e6980ea198be3a5a47509d58bf53bf460b4787ed5dab0f6c034059e39830b5a57f8236dca4ae
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+ .byebug_history
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.5.0
7
+ before_install: gem install bundler -v 1.16.6
File without changes
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at storkyd@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "https://rubygems.org"
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in japan_shipping_csv.gemspec
6
+ gemspec
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ japan_shipping_csv (0.2.2)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ minitest (5.14.1)
10
+ rake (10.5.0)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ bundler (~> 1.16)
17
+ japan_shipping_csv!
18
+ minitest (~> 5.0)
19
+ rake (~> 10.0)
20
+
21
+ BUNDLED WITH
22
+ 1.16.6
@@ -0,0 +1,39 @@
1
+ # JapanShippingCsv
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/japan_shipping_csv`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'japan_shipping_csv'
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install japan_shipping_csv
22
+
23
+ ## Usage
24
+
25
+ TODO: Write usage instructions here
26
+
27
+ ## Development
28
+
29
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
+
31
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
32
+
33
+ ## Contributing
34
+
35
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/japan_shipping_csv. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
+
37
+ ## Code of Conduct
38
+
39
+ Everyone interacting in the JapanShippingCsv project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/japan_shipping_csv/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList["test/**/*_test.rb"]
8
+ end
9
+
10
+ task :default => :test
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "japan_shipping_csv"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,40 @@
1
+ lib = File.expand_path("../lib", __FILE__)
2
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
+ require "japan_shipping_csv/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "japan_shipping_csv"
7
+ spec.version = JapanShippingCSV::VERSION
8
+ spec.authors = ["Shaun Cechner"]
9
+ spec.email = ["shaun@brewkeeper.com.au"]
10
+
11
+ spec.summary = %q{Export orders to Japan Shipping Carrier compatible CSV.}
12
+ # spec.description = %q{TODO: Write a longer description or delete this line.}
13
+ spec.homepage = "https://gitlab.com/brewkeeper/japan-shipping-csv"
14
+
15
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
16
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
17
+ if spec.respond_to?(:metadata)
18
+ # spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
19
+
20
+ spec.metadata["homepage_uri"] = spec.homepage
21
+ # spec.metadata["source_code_uri"] = "TODO: Put your gem's public repo URL here."
22
+ spec.metadata["changelog_uri"] = "https://gitlab.com/brewkeeper/japan-shipping-csv/-/blob/master/CHANGELOG.md"
23
+ else
24
+ raise "RubyGems 2.0 or newer is required to protect against " \
25
+ "public gem pushes."
26
+ end
27
+
28
+ # Specify which files should be added to the gem when it is released.
29
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
30
+ spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
31
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
32
+ end
33
+ spec.bindir = "exe"
34
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
35
+ spec.require_paths = ["lib"]
36
+
37
+ spec.add_development_dependency "bundler", "~> 1.16"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+ spec.add_development_dependency "minitest", "~> 5.0"
40
+ end
@@ -0,0 +1,3 @@
1
+ require "japan_shipping_csv/version"
2
+ require "japan_shipping_csv/ehiden"
3
+ require "japan_shipping_csv/encoding"
@@ -0,0 +1,220 @@
1
+ require 'csv'
2
+
3
+ module JapanShippingCSV
4
+ module Ehiden
5
+ FieldSpec = Struct.new(:header, :description, :is_required, :max_length, :valid_encodings, :valid_values, :default_value) do
6
+ def encoding_errors(value)
7
+ if !is_required && (value.nil? || value.empty?)
8
+ return []
9
+ end
10
+ if is_required && (value.nil? || value.empty?)
11
+ return ["value is required"]
12
+ end
13
+
14
+ results = []
15
+
16
+ if !valid_values.nil? && !valid_values.include?(value)
17
+ results << "must be one of #{valid_values.join(", ")}"
18
+ end
19
+ if value.length > max_length
20
+ results << "is longer than #{max_length} characters"
21
+ end
22
+ if valid_encodings
23
+ # TODO
24
+ # go through each character in the value, and veriy that it matches the valid encodings
25
+ if !Encoding::is_valid_string(value, valid_encodings)
26
+ results << "contains invalid character"
27
+ end
28
+ end
29
+ results
30
+ end
31
+ end
32
+
33
+ class Field
34
+ attr_reader :spec, :value
35
+
36
+ def initialize(spec, value)
37
+ @spec = spec
38
+ @value = value || @spec.default_value
39
+ @value = Encoding::reencode(@value, @spec.valid_encodings)
40
+ end
41
+
42
+ def encoding_errors
43
+ @spec.encoding_errors(@value)
44
+ end
45
+ end
46
+
47
+ class CSV
48
+ def initialize(options = {})
49
+ package_codes = ["001", "002", "003", "004", "005", "006", "007", "008"]
50
+ # auto packageCodes = QStringList()
51
+ # << QString("|")
52
+ # << QString("001|%1").arg(tr("Boxed Goods"))
53
+ # << QString("002|%1").arg(tr("Bagged Goods"))
54
+ # << QString("003|%1").arg(tr("Suitcase"))
55
+ # << QString("004|%1").arg(tr("Envelope"))
56
+ # << QString("005|%1").arg(tr("Golf Bag"))
57
+ # << QString("006|%1").arg(tr("Skis"))
58
+ # << QString("007|%1").arg(tr("Snowboard"))
59
+ # << QString("008|%1").arg(tr("Other"))
60
+ delivery_speeds = ["000", "001", "002", "003", "004", "005"]
61
+ # << QString("|")
62
+ # << QString("000|%1").arg(tr("Courier Service"))
63
+ # << QString("001|%1").arg(tr("Supermarket"))
64
+ # << QString("002|%1").arg(tr("Immediate Flight"))
65
+ # << QString("003|%1").arg(tr("Air Mail (next day delivery)"))
66
+ # << QString("004|%1").arg(tr("Air Mail (next morning delivery)"))
67
+ # << QString("005|%1").arg(tr("\"Just Time\" Flight"))
68
+ delivery_types = ["001", "002", "003"]
69
+ # << QString("|")
70
+ # << QString("001|%1").arg(tr("Regular"))
71
+ # << QString("002|%1").arg(tr("Cool Shipping"))
72
+ # << QString("003|%1").arg(tr("Frozen Shipping"))
73
+ time_types = ["01", "12", "14", "16", "04"]
74
+ # << QString("|")
75
+ # << QString("01|%1").arg(tr("09:00-12:00"))
76
+ # << QString("12|%1").arg(tr("12:00-14:00"))
77
+ # << QString("14|%1").arg(tr("14:00-16:00"))
78
+ # << QString("16|%1").arg(tr("16:00-18:00"))
79
+ # << QString("04|%1").arg(tr("18:00-21:00"))
80
+ seal_types = ["001", "002", "005", "007", "008", "016"]
81
+ # << QString("|")
82
+ # << QString("001|%1").arg(tr("Cool Shipping"))
83
+ # << QString("002|%1").arg(tr("Frozen Shipping"))
84
+ # << QString("005|%1").arg(tr("Specific Day Delivery"))
85
+ # << QString("007|%1").arg(tr("Specifc Time Delivery"))
86
+ # << QString("008|%1").arg(tr("Cash-On-Delivery"))
87
+ # << QString("016|%1").arg(tr("Specific Time Delivery (AM)"))
88
+
89
+ defaults = options[:default_field_values] || {}
90
+
91
+ @field_infos = {
92
+ address_code: FieldSpec.new("住所録コード", "Address Code", false, 12, Encoding::HALFWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
93
+ shipping_phone_number: FieldSpec.new("お届け先電話番号", "Shipping Phone Number", false, 14, Encoding::HALFWIDTH | Encoding::NUMBERS | Encoding::HYPHEN, nil, nil),
94
+ shipping_postal_code: FieldSpec.new("お届け先郵便番号", "Shipping Postal Code", false, 8, Encoding::HALFWIDTH | Encoding::NUMBERS | Encoding::HYPHEN, nil, nil),
95
+ shipping_address1: FieldSpec.new("お届け先住所1", "Shipping Address 1", true, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
96
+ shipping_address2: FieldSpec.new("お届け先住所2", "Shipping Address 2", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
97
+ shipping_address3: FieldSpec.new("お届け先住所3", "Shipping Address 3", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
98
+ shipping_name1: FieldSpec.new("お届け先名称1", "Shipping Name 1", true, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
99
+ shipping_name2: FieldSpec.new("お届け先名称2", "Shipping Name 2", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
100
+ shipping_customer_admin_number: FieldSpec.new("お客様管理ナンバー", "Shipping Customer Admin Number", false, 16, Encoding::HALFWIDTH | Encoding::ROMAJI, nil, nil),
101
+ customer_code: FieldSpec.new("お客様コード", "Customer Code", false, 12, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, defaults[:customer_code]),
102
+ person_and_division_in_charge: FieldSpec.new("部署・担当者", "Person And Division In Charge", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
103
+ shipping_persons_number: FieldSpec.new("荷送人電話番号", "Shipping Persons Number", false, 14, Encoding::HALFWIDTH | Encoding::NUMBERS | Encoding::HYPHEN, nil, defaults[:shipping_persons_number]),
104
+ shipping_requestors_phone_number: FieldSpec.new("ご依頼主電話番号", "Shipping Requestors Phone Number", false, 14, Encoding::HALFWIDTH | Encoding::NUMBERS | Encoding::HYPHEN, nil, defaults[:shipping_requestors_phone_number]),
105
+ shipping_requestors_postal_code: FieldSpec.new("ご依頼主郵便番号", "Shipping Requestors Postal Code", false, 8, Encoding::HALFWIDTH | Encoding::NUMBERS | Encoding::HYPHEN, nil, defaults[:shipping_requestors_postal_code]),
106
+ shipping_requestors_address_line_1: FieldSpec.new("ご依頼主住所1", "Shipping Requestors Address Line 1", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, defaults[:shipping_requestors_address_line_1]),
107
+ shipping_requestors_address_line_2: FieldSpec.new("ご依頼主住所2", "Shipping Requestors Address Line 2", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, defaults[:shipping_requestors_address_line_1]),
108
+ shipping_requestors_name_line_1: FieldSpec.new("ご依頼主名称1", "Shipping Requestors Name Line 1", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, defaults[:shipping_requestors_name_line_1]),
109
+ shipping_requestors_name_line_2: FieldSpec.new("ご依頼主名称2", "Shipping Requestors Name Line 2", false, 16, Encoding::FULLWIDTH | Encoding::ROMAJI | Encoding::NUMBERS | Encoding::KATAKANA, nil, nil),
110
+ package_code: FieldSpec.new("荷姿コード", "Package Code", false, 3, Encoding::HALFWIDTH | Encoding::NUMBERS, package_codes, defaults[:package_code]),
111
+ item1: FieldSpec.new("品名1", "Item 1", false, 16, Encoding::FULLWIDTH, nil, nil),
112
+ item2: FieldSpec.new("品名2", "Item 2", false, 16, Encoding::FULLWIDTH, nil, nil),
113
+ item3: FieldSpec.new("品名3", "Item 3", false, 16, Encoding::FULLWIDTH, nil, nil),
114
+ item4: FieldSpec.new("品名4", "Item 4", false, 16, Encoding::FULLWIDTH, nil, nil),
115
+ item5: FieldSpec.new("品名5", "Item 5", false, 16, Encoding::FULLWIDTH, nil, nil),
116
+ item_count: FieldSpec.new("出荷個数", "Item Count", false, 3, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, nil),
117
+ delivery_speed: FieldSpec.new("便種(スピードで選択)", "Delivery Speed", false, 3, Encoding::HALFWIDTH | Encoding::NUMBERS, delivery_speeds, defaults[:delivery_speed]),
118
+ delivery_type: FieldSpec.new("便種(商品)", "Delivery Type", false, 3, Encoding::HALFWIDTH | Encoding::NUMBERS, delivery_types, defaults[:delivery_type]),
119
+ delivery_date: FieldSpec.new("配達日", "Delivery Date", false, 8, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, nil),
120
+ delivery_time1: FieldSpec.new("配達指定時間帯", "Delivery Time 1", false, 2, Encoding::HALFWIDTH | Encoding::NUMBERS, time_types, nil),
121
+ delivery_time2: FieldSpec.new("配達指定時間(時分)", "Delivery Time 2", false, 4, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, nil),
122
+ cod_amount: FieldSpec.new("代引金額", "COD Amount", false, 7, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, nil),
123
+ included_tax_amount: FieldSpec.new("消費税", "Included Tax Amount", false, 6, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, nil),
124
+ cod_payment_method: FieldSpec.new("決済種別", "COD Payment Method", false, 1, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, defaults[:cod_payment_method]),
125
+ insured_amount: FieldSpec.new("保険金額", "Insured Amount", false, 8, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, defaults[:insured_amount]),
126
+ display_insured_amount: FieldSpec.new("保険金額印字", "Display Insured Amount", false, 1, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, defaults[:display_insured_amount]),
127
+ seal1: FieldSpec.new("指定シール1", "Seal 1", false, 3, Encoding::HALFWIDTH | Encoding::NUMBERS, seal_types, nil),
128
+ seal2: FieldSpec.new("指定シール2", "Seal 2", false, 3, Encoding::HALFWIDTH | Encoding::NUMBERS, seal_types, nil),
129
+ seal3: FieldSpec.new("指定シール3", "Seal 3", false, 3, Encoding::HALFWIDTH | Encoding::NUMBERS, seal_types, nil),
130
+ stops_at_delivery_centre: FieldSpec.new("営業店止め", "Stops At Delivery Centre", false, 1, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, defaults[:stops_at_delivery_centre]),
131
+ sagawa_logistics_centre: FieldSpec.new("SRC区分", "Sagawa Logistics Centre", false, 1, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, defaults[:sagawa_logistics_centre]),
132
+ sagawa_centre_code: FieldSpec.new("営業店コード", "Sagawa Centre Code", false, 4, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, nil),
133
+ payment_style: FieldSpec.new("元着区分", "Payment Style", false, 1, Encoding::HALFWIDTH | Encoding::NUMBERS, nil, defaults[:payment_style])
134
+ }
135
+ # e.g., {0 => {shipping_name: Field}}
136
+ @next_row_id = 0
137
+ @row_fields = Hash.new { |h, k| h[k] = Hash.new() }
138
+ end
139
+
140
+ def row_ids
141
+ @row_fields.keys
142
+ end
143
+
144
+ def field_names
145
+ @field_infos.keys
146
+ end
147
+
148
+ def add_row
149
+ result = @next_row_id + 1
150
+ @next_row_id += 1
151
+ result
152
+ end
153
+
154
+ def set_field_value(row_id, field_name, field_value)
155
+ row = @row_fields[row_id]
156
+ field_info = @field_infos[field_name]
157
+ raise "unrecognised field #{field_name}" if field_info.nil?
158
+
159
+ field = Field.new(field_info, field_value)
160
+ row[field_name] = field
161
+ end
162
+
163
+ def add_row_values(values = {})
164
+ row_id = add_row
165
+ values.each do |field_name, field_value|
166
+ set_field_value(row_id, field_name, field_value)
167
+ end
168
+ row_id
169
+ end
170
+
171
+ def get_field_value(row_id, field_name)
172
+ row = @row_fields[row_id]
173
+ field_info = @field_infos[field_name]
174
+ field = row[field_name]
175
+ if field.nil?
176
+ field = Field.new(field_info, nil)
177
+ end
178
+ field.value || ""
179
+ end
180
+
181
+ def get_field_error(row_id, field_name)
182
+ row = @row_fields[row_id]
183
+ field_info = @field_infos[field_name]
184
+ field = row[field_name]
185
+ if field.nil?
186
+ field = Field.new(field_info, nil)
187
+ end
188
+ field.encoding_errors || ""
189
+ end
190
+
191
+ def encoding_errors
192
+ result = {}
193
+ @row_fields.each do |row_id, fields|
194
+ errors = fields.select { |_n, f| f.encoding_errors.any? }
195
+ result[row_id] = errors unless errors.empty?
196
+ end
197
+ result
198
+ end
199
+
200
+ def to_csv(options = {})
201
+ field_headers = @field_infos.map { |_k, v| v.header.encode(::Encoding::SJIS) }
202
+ ::CSV.generate(options) do |csv|
203
+ csv << field_headers
204
+
205
+ @row_fields.each do |row|
206
+ row_data = field_names.map do |field_name|
207
+ field_value = get_field_value(row[0], field_name)
208
+ begin
209
+ field_value.gsub("−", "‐").encode(::Encoding::SJIS)
210
+ rescue => ex
211
+ raise "could not encode field #{field_name} (value #{field_value}) - #{ex.message}"
212
+ end
213
+ end
214
+ csv << row_data
215
+ end
216
+ end
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,162 @@
1
+ require 'nkf'
2
+
3
+ module JapanShippingCSV
4
+ module Encoding
5
+ # Eg. HALFWIDTH + ROMAJI + NUMBERS can be represented by:
6
+ # valid_encodings = Encoding::HALFWIDTH | Encoding::ROMAJI | Encoding::NUMBERS
7
+ # and to figure out whether a flag is set:
8
+ # romaji_allowed? = valid_encodings & Encoding::ROMAJI
9
+ # 0 = false, 1 = true (which is not true in ruby)
10
+ HALFWIDTH = 1 # Hankaku
11
+ FULLWIDTH = 2 # Zenkaku
12
+ ROMAJI = 4
13
+ NUMBERS = 8
14
+ KATAKANA = 16
15
+ HYPHEN = 32
16
+
17
+ module CodePoints
18
+ # Character set lower/upper bound definitions
19
+ ## Bounds for Hiragana
20
+ ZENKAKU_HIRAGANA_FIRST = 'ぁ' # U+3041
21
+ ZENKAKU_HIRAGANA_LAST_FOR_CONVERT = 'ん' # U+3093
22
+ ZENKAKU_HIRAGANA_LAST = 'ゖ' # U+3096
23
+
24
+ ## Bounds for Katakana
25
+ HANKAKU_KATAKANA_FIRST = 'ヲ' # U+FF66
26
+ HANKAKU_KATAKANA_LAST = 'ン' # U+FF9D
27
+
28
+ ZENKAKU_KATAKANA_FIRST = 'ァ' # U+30A1
29
+ ZENKAKU_KATAKANA_LAST_FOR_CONVERT = 'ン' # U+30F3
30
+ ZENKAKU_KATAKANA_LAST = 'ヺ' # U+30FA
31
+
32
+ ## Bounds for Punctuation (kutoten)
33
+ HANKAKU_PUNCTUATION_FIRST = '。' # U+FF61
34
+ HANKAKU_PUNCTUATION_LAST = '゚' # U+FF9F
35
+ HANKAKU_PUNCTUATION_ONBIKI = 'ー' # U+FF70
36
+
37
+ ZENKAKU_PUNCTUATION_FIRST = '、' # U+3001
38
+ ZENKAKU_PUNCTUATION_LAST = '〜' # U+301C
39
+ ZENKAKU_PUNCTUATION_HG_FIRST = '゛' # U+309B
40
+ ZENKAKU_PUNCTUATION_HG_LAST = 'ゞ' # U+309E
41
+ ZENKAKU_PUNCTUATION_KK_FIRST = '・' # U+30FB
42
+ ZENKAKU_PUNCTUATION_KK_LAST = 'ヾ' # U+30FE
43
+
44
+ ## Bounds for Numeric
45
+ HANKAKU_NUMBER_FIRST = '0' # U+0030
46
+ HANKAKU_NUMBER_LAST = '9' # U+0039
47
+
48
+ ZENKAKU_NUMBER_FIRST = '0' # U+FF10
49
+ ZENKAKU_NUMBER_LAST = '9' # U+FF19
50
+
51
+ ## Bounds for Alphabetic
52
+ HANKAKU_LETTER_UPPER_FIRST = 'A' # U+0041
53
+ HANKAKU_LETTER_UPPER_LAST = 'Z' # U+005A
54
+ HANKAKU_LETTER_LOWER_FIRST = 'a' # U+0061
55
+ HANKAKU_LETTER_LOWER_LAST = 'z' # U+007A
56
+
57
+ ZENKAKU_LETTER_UPPER_FIRST = 'A' # U+FF21
58
+ ZENKAKU_LETTER_UPPER_LAST = 'Z' # U+FF3A
59
+ ZENKAKU_LETTER_LOWER_FIRST = 'a' # U+FF41
60
+ ZENKAKU_LETTER_LOWER_LAST = 'z' # U+FF5A
61
+
62
+ # Bounds for All Alphanumeric and Symbol ASCII
63
+ HANKAKU_SPACE = ' ' # U+0020
64
+ HANKAKU_ASCII_FIRST = '!' # U+0021
65
+ HANKAKU_ASCII_LAST = '~' # U+007E
66
+
67
+ ZENKAKU_SPACE = ' ' # U+3000
68
+ ZENKAKU_ASCII_FIRST = '!' # U+FF01
69
+ ZENKAKU_ASCII_LAST = '~' # U+FF5E
70
+ end
71
+
72
+ class << self
73
+ def reencode(value, encoding_flags)
74
+ return value if value.nil?
75
+
76
+ result = value
77
+ # if half-width not allowed
78
+ half_width_allowed = (encoding_flags & Encoding::HALFWIDTH) == Encoding::HALFWIDTH
79
+ if half_width_allowed
80
+ result = NKF.nkf('-X -w', value).tr('0-9a-zA-Z -', '0-9a-zA-Z -')
81
+ end
82
+ # if full-width not allowed
83
+ fullwidth_allowed = (encoding_flags & Encoding::FULLWIDTH) == Encoding::FULLWIDTH
84
+ if fullwidth_allowed
85
+ result = NKF.nkf('-X -w', value).tr('0-9a-zA-Z -', '0-9a-zA-Z -').tr(''', '’')
86
+ end
87
+ result
88
+ end
89
+
90
+ def is_romaji(value)
91
+ return false if value.empty?
92
+
93
+ value.split("").each do |c|
94
+ # return !(::kana::isHankakuLetter(u) || ::kana::isZenkakuLetter(u));
95
+ is_hankaku_upper = c >= CodePoints::HANKAKU_LETTER_UPPER_FIRST && c <= CodePoints::HANKAKU_LETTER_UPPER_LAST
96
+ is_hankaku_lower = c >= CodePoints::HANKAKU_LETTER_LOWER_FIRST && c <= CodePoints::HANKAKU_LETTER_LOWER_LAST
97
+ is_zenkaku_upper = c >= CodePoints::ZENKAKU_LETTER_UPPER_FIRST && c <= CodePoints::ZENKAKU_LETTER_UPPER_LAST
98
+ is_zenkaku_lower = c >= CodePoints::ZENKAKU_LETTER_LOWER_FIRST && c <= CodePoints::ZENKAKU_LETTER_LOWER_LAST
99
+ return false if !is_hankaku_upper && !is_hankaku_lower && !is_zenkaku_upper && !is_zenkaku_lower
100
+ end
101
+ true
102
+ end
103
+
104
+ def is_number(value)
105
+ return false if value.empty?
106
+
107
+ value.split("").each do |c|
108
+ is_hankaku_number = c >= CodePoints::HANKAKU_NUMBER_FIRST && c <= CodePoints::HANKAKU_NUMBER_LAST
109
+ is_zenkaku_number = c >= CodePoints::ZENKAKU_NUMBER_FIRST && c <= CodePoints::ZENKAKU_NUMBER_LAST
110
+ return false if !is_hankaku_number && !is_zenkaku_number
111
+ end
112
+ true
113
+ end
114
+
115
+ def is_katakana(value)
116
+ return false if value.empty?
117
+
118
+ value.split("").each do |c|
119
+ is_hankaku_katakana = c >= CodePoints::HANKAKU_KATAKANA_FIRST && c <= CodePoints::HANKAKU_KATAKANA_LAST && c != CodePoints::HANKAKU_PUNCTUATION_ONBIKI
120
+ is_zenkaku_katakana = c >= CodePoints::ZENKAKU_KATAKANA_FIRST && c <= CodePoints::ZENKAKU_KATAKANA_LAST
121
+ return false if !is_hankaku_katakana && !is_zenkaku_katakana
122
+ end
123
+ true
124
+ end
125
+
126
+ def is_hyphen(value)
127
+ return false if value.empty?
128
+
129
+ value.split("").each do |c|
130
+ if c != '-' && c != '-' && c != 'ー' && c != 'ー'
131
+ return false
132
+ end
133
+ end
134
+ true
135
+ end
136
+
137
+ def is_valid_string(value, encoding_flags)
138
+ value.split("").each do |c|
139
+ # if is_half_width(c) && !(encoding_flags & Encoding::HALFWIDTH)
140
+ # return false
141
+ # end
142
+ # if is_full_width(c) && !(encoding_flags & Encoding::FULLWIDTH)
143
+ # return false
144
+ # end
145
+ if is_romaji(c) && !(encoding_flags & Encoding::ROMAJI)
146
+ return false
147
+ end
148
+ if is_number(c) && !(encoding_flags & Encoding::NUMBERS)
149
+ return false
150
+ end
151
+ if is_katakana(c) && !(encoding_flags & Encoding::KATAKANA)
152
+ return false
153
+ end
154
+ if is_hyphen(c) && !(encoding_flags & Encoding::HYPHEN)
155
+ return false
156
+ end
157
+ end
158
+ return true
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,3 @@
1
+ module JapanShippingCSV
2
+ VERSION = "0.2.2"
3
+ end
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: japan_shipping_csv
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.2
5
+ platform: ruby
6
+ authors:
7
+ - Shaun Cechner
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2020-06-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '5.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '5.0'
55
+ description:
56
+ email:
57
+ - shaun@brewkeeper.com.au
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - ".gitignore"
63
+ - ".travis.yml"
64
+ - CHANGELOG.md
65
+ - CODE_OF_CONDUCT.md
66
+ - Gemfile
67
+ - Gemfile.lock
68
+ - README.md
69
+ - Rakefile
70
+ - bin/console
71
+ - bin/setup
72
+ - japan_shipping_csv.gemspec
73
+ - lib/japan_shipping_csv.rb
74
+ - lib/japan_shipping_csv/ehiden.rb
75
+ - lib/japan_shipping_csv/encoding.rb
76
+ - lib/japan_shipping_csv/version.rb
77
+ homepage: https://gitlab.com/brewkeeper/japan-shipping-csv
78
+ licenses: []
79
+ metadata:
80
+ homepage_uri: https://gitlab.com/brewkeeper/japan-shipping-csv
81
+ changelog_uri: https://gitlab.com/brewkeeper/japan-shipping-csv/-/blob/master/CHANGELOG.md
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.7.8
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Export orders to Japan Shipping Carrier compatible CSV.
102
+ test_files: []