fruit_to_lime 2.0.1 → 2.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.
- data/lib/fruit_to_lime.rb +1 -1
- data/lib/fruit_to_lime/model/address.rb +24 -1
- data/lib/fruit_to_lime/model/deal.rb +1 -1
- data/lib/fruit_to_lime/model/organization.rb +8 -21
- data/lib/fruit_to_lime/model/person.rb +8 -13
- data/lib/fruit_to_lime/model/referencetosource.rb +1 -1
- data/lib/fruit_to_lime/model/rootmodel.rb +8 -13
- data/lib/fruit_to_lime/model/settings.rb +2 -0
- data/lib/fruit_to_lime/model/tag.rb +2 -1
- data/lib/fruit_to_lime/model_helpers.rb +5 -7
- data/lib/fruit_to_lime/serialize_helper.rb +10 -0
- data/spec/{helpers/address_helper_spec.rb → address_spec.rb} +1 -1
- data/spec/helpers/serialize_helper_spec.rb +5 -5
- data/spec/helpers/xsd_validate_spec.rb +2 -2
- data/templates/csv/export.xml +152 -0
- data/templates/csv/lib/tomodel.rb +182 -19
- data/templates/csv/spec/exporter_spec.rb +17 -0
- data/templates/csv/spec/sample_data/coworkers.csv +2 -0
- data/templates/csv/spec/sample_data/deals.csv +2 -0
- data/templates/csv/spec/sample_data/organizations.csv +2 -2
- data/templates/csv/spec/sample_data/persons.csv +2 -0
- metadata +9 -6
- data/lib/fruit_to_lime/address_helper.rb +0 -18
- data/templates/csv/spec/tomodel_spec.rb +0 -14
data/lib/fruit_to_lime.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module FruitToLime
|
2
|
+
private
|
2
3
|
def self.require_all_in(folder)
|
3
4
|
Dir.glob(File.join( File.dirname(File.absolute_path(__FILE__)),folder), &method(:require))
|
4
5
|
end
|
5
6
|
|
6
7
|
require 'fruit_to_lime/serialize_helper'
|
7
|
-
require 'fruit_to_lime/address_helper'
|
8
8
|
require 'fruit_to_lime/model_helpers'
|
9
9
|
FruitToLime::require_all_in 'fruit_to_lime/model/*.rb'
|
10
10
|
require 'fruit_to_lime/csv_helper'
|
@@ -9,11 +9,14 @@ module FruitToLime
|
|
9
9
|
def initialize()
|
10
10
|
end
|
11
11
|
|
12
|
+
# What fields/rows on the class is supposed to be used by the Gem to generate the xml
|
13
|
+
# This method uses {#serialize_variables}. It also adds {#country_name} to be serialized
|
12
14
|
def get_import_rows
|
13
15
|
(serialize_variables+[{:id=>:country_name, :type=>:string}]).map do |p|
|
14
16
|
map_to_row p
|
15
17
|
end
|
16
18
|
end
|
19
|
+
# Used as a convenience in order to get country code from internally used {#country_code}
|
17
20
|
def country_name
|
18
21
|
if @country_code
|
19
22
|
IsoCountryCodes.find(@country_code).name
|
@@ -21,6 +24,8 @@ module FruitToLime
|
|
21
24
|
nil
|
22
25
|
end
|
23
26
|
end
|
27
|
+
|
28
|
+
# Used as a convenience in order to map country name to the internal {#country_code}
|
24
29
|
def country_name=(name)
|
25
30
|
@country_code = case name
|
26
31
|
when nil
|
@@ -31,8 +36,26 @@ module FruitToLime
|
|
31
36
|
IsoCountryCodes.search_by_name(name).first.alpha2
|
32
37
|
end
|
33
38
|
end
|
39
|
+
# parses a line like "226 48 LUND" into its corresponding
|
40
|
+
# zipcode and city properties on the address
|
34
41
|
def parse_zip_and_address_se(line)
|
35
|
-
|
42
|
+
Address.parse_line_to_zip_and_address_se(line, self)
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
def self.parse_line_to_zip_and_address_se(line, address)
|
47
|
+
matched_zipcode = /^\d{3}\s?\d{2}/.match(line)
|
48
|
+
if matched_zipcode && matched_zipcode.length == 1
|
49
|
+
address.zip_code = matched_zipcode[0].strip()
|
50
|
+
matched_city = /\D*$/.match(line)
|
51
|
+
if matched_city && matched_city.length == 1
|
52
|
+
address.city = matched_city[0].strip()
|
53
|
+
return address
|
54
|
+
end
|
55
|
+
end
|
56
|
+
return nil
|
36
57
|
end
|
58
|
+
|
59
|
+
|
37
60
|
end
|
38
61
|
end
|
@@ -5,7 +5,7 @@ module FruitToLime
|
|
5
5
|
|
6
6
|
attr_accessor :id, :integration_id, :name, :description, :probability, :value, :order_date, :offer_date, :customer,
|
7
7
|
:responsible_coworker, :customer_contact, :status
|
8
|
-
|
8
|
+
# you add custom values by using {#set_custom_value}
|
9
9
|
attr_reader :custom_values
|
10
10
|
|
11
11
|
def serialize_variables
|
@@ -19,25 +19,6 @@ module FruitToLime
|
|
19
19
|
def empty?
|
20
20
|
return !@integration_id && !@id && !@heading
|
21
21
|
end
|
22
|
-
|
23
|
-
# *** TODO: delete this?
|
24
|
-
def same_as_this_method()
|
25
|
-
if @integration_id
|
26
|
-
return lambda { |org|
|
27
|
-
org.integration_id == @integration_id
|
28
|
-
}
|
29
|
-
elsif @id
|
30
|
-
return lambda { |org|
|
31
|
-
org.id == @id
|
32
|
-
}
|
33
|
-
elsif @heading
|
34
|
-
return lambda { |org|
|
35
|
-
org.heading == @heading
|
36
|
-
}
|
37
|
-
else
|
38
|
-
raise "No reference!"
|
39
|
-
end
|
40
|
-
end
|
41
22
|
end
|
42
23
|
|
43
24
|
class Organization
|
@@ -89,7 +70,7 @@ module FruitToLime
|
|
89
70
|
end
|
90
71
|
|
91
72
|
def add_employee(val)
|
92
|
-
@employees = [] if @employees==nil
|
73
|
+
@employees = [] if @employees == nil
|
93
74
|
person = if val.is_a? Person then val else Person.new(val) end
|
94
75
|
@employees.push(person)
|
95
76
|
person
|
@@ -101,6 +82,12 @@ module FruitToLime
|
|
101
82
|
coworker
|
102
83
|
end
|
103
84
|
|
85
|
+
def find_employee_by_integration_id(integration_id)
|
86
|
+
return @employees.find do |e|
|
87
|
+
e.integration_id == integration_id
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
104
91
|
def serialize_variables
|
105
92
|
[
|
106
93
|
{ :id => :id, :type => :string },
|
@@ -127,7 +114,7 @@ module FruitToLime
|
|
127
114
|
def to_s
|
128
115
|
return "#{name}"
|
129
116
|
end
|
130
|
-
|
117
|
+
|
131
118
|
def validate
|
132
119
|
error = String.new
|
133
120
|
|
@@ -14,19 +14,6 @@ module FruitToLime
|
|
14
14
|
def empty?
|
15
15
|
return !@integration_id && !@id
|
16
16
|
end
|
17
|
-
def same_as_this_method()
|
18
|
-
if @integration_id
|
19
|
-
return lambda { |person|
|
20
|
-
person.integration_id == @integration_id
|
21
|
-
}
|
22
|
-
elsif @id
|
23
|
-
return lambda { |person|
|
24
|
-
person.id == @id
|
25
|
-
}
|
26
|
-
else
|
27
|
-
raise "No reference!"
|
28
|
-
end
|
29
|
-
end
|
30
17
|
end
|
31
18
|
|
32
19
|
class Person < PersonReference
|
@@ -35,6 +22,7 @@ module FruitToLime
|
|
35
22
|
:direct_phone_number, :fax_phone_number, :mobile_phone_number, :home_phone_number,
|
36
23
|
:position, :email, :alternative_email, :postal_address, :currently_employed,
|
37
24
|
:organization
|
25
|
+
# you add custom values by using {#set_custom_value}
|
38
26
|
attr_reader :custom_values
|
39
27
|
|
40
28
|
def initialize(opt = nil)
|
@@ -93,6 +81,13 @@ module FruitToLime
|
|
93
81
|
]
|
94
82
|
end
|
95
83
|
|
84
|
+
def to_reference()
|
85
|
+
reference = PersonReference.new
|
86
|
+
reference.id = @id
|
87
|
+
reference.integration_id = @integration_id
|
88
|
+
return reference
|
89
|
+
end
|
90
|
+
|
96
91
|
def get_import_rows
|
97
92
|
(serialize_variables + [ { :id => :organization, :type => :organization_reference } ]).map do |p|
|
98
93
|
map_to_row p
|
@@ -36,7 +36,7 @@ module FruitToLime
|
|
36
36
|
end
|
37
37
|
return @name == other.name && @id == other.id && @format== other.format
|
38
38
|
end
|
39
|
-
|
39
|
+
# Sets the id of this instance to the parameter supplied. Will also set {#name} and {#format} so that this reference is identified as a PAR identifier by Go.
|
40
40
|
def par_se(id)
|
41
41
|
@name = 'pase'
|
42
42
|
@format = 'External'
|
@@ -1,9 +1,12 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
module FruitToLime
|
3
|
+
# The root model for Go import. This class is the container for everything else.
|
3
4
|
class RootModel
|
4
5
|
# the import_coworker is a special coworker that is set as
|
5
6
|
# responsible for objects that requires a coworker, eg a note.
|
6
|
-
attr_accessor :
|
7
|
+
attr_accessor :import_coworker
|
8
|
+
|
9
|
+
attr_accessor :settings, :organizations, :coworkers, :deals, :notes
|
7
10
|
def serialize_variables
|
8
11
|
[
|
9
12
|
{:id => :settings, :type => :settings},
|
@@ -54,17 +57,6 @@ module FruitToLime
|
|
54
57
|
yield note
|
55
58
|
end
|
56
59
|
|
57
|
-
# *** TODO:
|
58
|
-
#
|
59
|
-
# delete find_organization_by_reference and
|
60
|
-
#same_as_this_method from organization?
|
61
|
-
def find_organization_by_reference(organization_reference)
|
62
|
-
same_as_this = organization_reference.same_as_this_method
|
63
|
-
return @organizations.find do |org|
|
64
|
-
same_as_this.call(org)
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
60
|
def find_coworker_by_integration_id(integration_id)
|
69
61
|
return @coworkers.find do |coworker|
|
70
62
|
coworker == integration_id
|
@@ -77,6 +69,7 @@ module FruitToLime
|
|
77
69
|
end
|
78
70
|
end
|
79
71
|
|
72
|
+
# find deals for organization using {Organization#integration_id}
|
80
73
|
def find_deals_for_organization(organization)
|
81
74
|
deals = []
|
82
75
|
|
@@ -87,6 +80,7 @@ module FruitToLime
|
|
87
80
|
return deals
|
88
81
|
end
|
89
82
|
|
83
|
+
# Returns a string describing problems with the data. For instance if integration_id for any entity is not unique.
|
90
84
|
def sanity_check
|
91
85
|
error = String.new
|
92
86
|
|
@@ -113,7 +107,7 @@ module FruitToLime
|
|
113
107
|
|
114
108
|
# returns all items from the object array with duplicate keys.
|
115
109
|
# To get all organizations with the same integration_id use
|
116
|
-
# get_duplicates(organizations, {|org| org.integration_id})
|
110
|
+
# `get_duplicates(organizations, {|org| org.integration_id})`
|
117
111
|
def get_duplicates(objects, &key)
|
118
112
|
uniq_items = objects.uniq {|item| key.call(item)}.compact
|
119
113
|
|
@@ -142,6 +136,7 @@ module FruitToLime
|
|
142
136
|
return error.strip
|
143
137
|
end
|
144
138
|
|
139
|
+
# @!visibility private
|
145
140
|
def to_rexml(doc)
|
146
141
|
element_name = serialize_name
|
147
142
|
elem = doc.add_element(element_name,{"Version"=>"v2_0"})
|
@@ -3,6 +3,7 @@ module FruitToLime
|
|
3
3
|
class Settings
|
4
4
|
include SerializeHelper
|
5
5
|
attr_reader :organization, :person, :deal
|
6
|
+
|
6
7
|
def with_organization
|
7
8
|
@organization = ClassSettings.new if @organization ==nil
|
8
9
|
yield @organization
|
@@ -15,6 +16,7 @@ module FruitToLime
|
|
15
16
|
@deal = ClassSettings.new if @deal ==nil
|
16
17
|
yield @deal
|
17
18
|
end
|
19
|
+
|
18
20
|
def initialize(opt = nil)
|
19
21
|
if opt != nil
|
20
22
|
serialize_variables.each do |myattr|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module FruitToLime
|
2
2
|
module ModelHasCustomFields
|
3
3
|
def set_custom_value(value, field)
|
4
|
-
@custom_values = [] if @custom_values==nil
|
4
|
+
@custom_values = [] if @custom_values == nil
|
5
5
|
custom_value = CustomValue.new()
|
6
6
|
custom_value.value = value
|
7
7
|
custom_value.field = field
|
@@ -15,6 +15,7 @@ module FruitToLime
|
|
15
15
|
@custom_values.push custom_value
|
16
16
|
return custom_value
|
17
17
|
end
|
18
|
+
# Note that this method is obsolete and will be removed later on. Please use {#set_custom_value}
|
18
19
|
def set_custom_field(obj)
|
19
20
|
value = obj[:value]
|
20
21
|
ref = CustomFieldReference.new(obj)
|
@@ -23,6 +24,7 @@ module FruitToLime
|
|
23
24
|
end
|
24
25
|
|
25
26
|
module ModelWithIntegrationIdSameAs
|
27
|
+
# check if other is same as regarding integration_id or id
|
26
28
|
def same_as?(other)
|
27
29
|
if @integration_id!=nil && @integration_id == other.integration_id
|
28
30
|
return true
|
@@ -34,14 +36,10 @@ module FruitToLime
|
|
34
36
|
end
|
35
37
|
end
|
36
38
|
|
37
|
-
module ModelHasTags
|
38
|
-
def add_tag(str)
|
39
|
-
@tags = [] if @tags == nil
|
40
|
-
@tags.push(Tag.new(str))
|
41
|
-
end
|
39
|
+
module ModelHasTags
|
42
40
|
def set_tag(str)
|
43
41
|
@tags = [] if @tags == nil
|
44
|
-
if ! @tags.any? {|tag| tag.value
|
42
|
+
if ! @tags.any? {|tag| tag.value == str }
|
45
43
|
@tags.push(Tag.new(str))
|
46
44
|
end
|
47
45
|
end
|
@@ -11,6 +11,7 @@ module FruitToLime
|
|
11
11
|
SerializeHelper::serialize_to_file(file, self)
|
12
12
|
end
|
13
13
|
|
14
|
+
# @!visibility private
|
14
15
|
def self.serialize_variables_rexml(elem, obj)
|
15
16
|
if (obj.respond_to?(:serialize_variables))
|
16
17
|
obj.serialize_variables.each do |serialize_variable|
|
@@ -37,6 +38,7 @@ module FruitToLime
|
|
37
38
|
raise "Do not know how to handle #{obj.class} !!"
|
38
39
|
end
|
39
40
|
|
41
|
+
# @!visibility private
|
40
42
|
def self.serialize_rexml(elem, obj)
|
41
43
|
if obj.respond_to?(:to_rexml)
|
42
44
|
obj.to_rexml(elem)
|
@@ -48,6 +50,7 @@ module FruitToLime
|
|
48
50
|
end
|
49
51
|
end
|
50
52
|
|
53
|
+
# @!visibility private
|
51
54
|
def self.serialize(obj, indent= 2)
|
52
55
|
# indent -1 to avoid indent
|
53
56
|
if obj.respond_to?(:to_rexml)
|
@@ -66,16 +69,19 @@ module FruitToLime
|
|
66
69
|
end
|
67
70
|
end
|
68
71
|
|
72
|
+
# @!visibility private
|
69
73
|
def self.serialize_to_file(file, obj)
|
70
74
|
File.open(file, 'w') do |f|
|
71
75
|
f.write(SerializeHelper::serialize(obj))
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
79
|
+
# @!visibility private
|
75
80
|
def symbol_to_name(symbol)
|
76
81
|
symbol.to_s.split('_').join(' ').capitalize
|
77
82
|
end
|
78
83
|
|
84
|
+
# @!visibility private
|
79
85
|
def map_symbol_to_row(symbol,type)
|
80
86
|
{
|
81
87
|
:id => symbol.to_s,
|
@@ -84,6 +90,7 @@ module FruitToLime
|
|
84
90
|
}
|
85
91
|
end
|
86
92
|
|
93
|
+
# @!visibility private
|
87
94
|
def map_to_row(p)
|
88
95
|
case p[:type]
|
89
96
|
when :string then
|
@@ -136,12 +143,15 @@ module FruitToLime
|
|
136
143
|
end
|
137
144
|
end
|
138
145
|
|
146
|
+
# What fields/rows on the class is supposed to be used by the Gem to generate the xml
|
147
|
+
# This method uses #serialize_variables.
|
139
148
|
def get_import_rows
|
140
149
|
serialize_variables.map do |p|
|
141
150
|
map_to_row p
|
142
151
|
end
|
143
152
|
end
|
144
153
|
|
154
|
+
# @!visibility private
|
145
155
|
def self.get_import_rows(type)
|
146
156
|
case type
|
147
157
|
when :person then
|
@@ -76,9 +76,9 @@ describe FruitToLime::SerializeHelper do
|
|
76
76
|
addr.city = "Ankeborg"
|
77
77
|
end
|
78
78
|
p.currently_employed=true
|
79
|
-
p.
|
80
|
-
p.
|
81
|
-
p.
|
79
|
+
p.set_tag("tag:anka")
|
80
|
+
p.set_tag("tag:Bj\u{00F6}rk")
|
81
|
+
p.set_tag("tag:<Bj\u{00F6}rk>")
|
82
82
|
p.set_custom_field({:integration_id=>"2", :value=>"cf value"})
|
83
83
|
p.set_custom_field({:integration_id=>"3", :value=>"cf Bj\u{00F6}rk"})
|
84
84
|
p.set_custom_field({:integration_id=>"4", :value=>"cf <Bj\u{00F6}rk>"})
|
@@ -127,8 +127,8 @@ describe FruitToLime::SerializeHelper do
|
|
127
127
|
source.par_se('122345')
|
128
128
|
end
|
129
129
|
#o.source_ref = {:name=>'Go',:id=>"PASE122345"}
|
130
|
-
o.
|
131
|
-
o.
|
130
|
+
o.set_tag("tag:bibliotek")
|
131
|
+
o.set_tag("tag:Bj\u{00F6}rk")
|
132
132
|
o.set_custom_field({:integration_id=>"2", :value=>"cf value"})
|
133
133
|
o.set_custom_field({:integration_id=>"3", :value=>"cf Bj\u{00F6}rk"})
|
134
134
|
o.with_postal_address do |addr|
|
@@ -17,8 +17,8 @@ describe FruitToLime::SerializeHelper do
|
|
17
17
|
source.par_se('122345')
|
18
18
|
end
|
19
19
|
#o.source_ref = {:name=>'Go',:id=>"PASE122345"}
|
20
|
-
o.
|
21
|
-
o.
|
20
|
+
o.set_tag("tag:bibliotek")
|
21
|
+
o.set_tag("tag:Bj\u{00F6}rk")
|
22
22
|
o.set_custom_field({:integration_id=>"2", :value=>"cf value"})
|
23
23
|
o.set_custom_field({:integration_id=>"3", :value=>"cf Bj\u{00F6}rk"})
|
24
24
|
o.with_postal_address do |addr|
|
@@ -0,0 +1,152 @@
|
|
1
|
+
<GoImport Version='v2_0'
|
2
|
+
><Settings
|
3
|
+
><Organization
|
4
|
+
><CustomFields
|
5
|
+
><CustomField
|
6
|
+
><Title
|
7
|
+
>Link to external system</Title
|
8
|
+
><Type
|
9
|
+
>Link</Type
|
10
|
+
></CustomField
|
11
|
+
></CustomFields
|
12
|
+
></Organization
|
13
|
+
></Settings
|
14
|
+
><Coworkers
|
15
|
+
><Coworker
|
16
|
+
><IntegrationId
|
17
|
+
>import</IntegrationId
|
18
|
+
><FirstName
|
19
|
+
>Import</FirstName
|
20
|
+
></Coworker
|
21
|
+
><Coworker
|
22
|
+
><IntegrationId
|
23
|
+
>666</IntegrationId
|
24
|
+
><FirstName
|
25
|
+
>Evil</FirstName
|
26
|
+
><LastName
|
27
|
+
>Elvis</LastName
|
28
|
+
><Email
|
29
|
+
>t@e.com</Email
|
30
|
+
><DirectPhoneNumber
|
31
|
+
>+46121212</DirectPhoneNumber
|
32
|
+
><MobilePhoneNumber
|
33
|
+
>+46324234</MobilePhoneNumber
|
34
|
+
><HomePhoneNumber
|
35
|
+
>+46234234</HomePhoneNumber
|
36
|
+
></Coworker
|
37
|
+
></Coworkers
|
38
|
+
><Organizations
|
39
|
+
><Organization
|
40
|
+
><IntegrationId
|
41
|
+
>6</IntegrationId
|
42
|
+
><Name
|
43
|
+
>Alfs Mjukvaruutveckling</Name
|
44
|
+
><OrganizationNumber
|
45
|
+
>a number</OrganizationNumber
|
46
|
+
><PostalAddress
|
47
|
+
><Street
|
48
|
+
>postal street</Street
|
49
|
+
><ZipCode
|
50
|
+
>226 48</ZipCode
|
51
|
+
><City
|
52
|
+
>LUND</City
|
53
|
+
></PostalAddress
|
54
|
+
><VisitAddress
|
55
|
+
><Street
|
56
|
+
>visit street</Street
|
57
|
+
><ZipCode
|
58
|
+
>visit zip</ZipCode
|
59
|
+
><City
|
60
|
+
>visit city</City
|
61
|
+
></VisitAddress
|
62
|
+
><CentralPhoneNumber
|
63
|
+
>0000</CentralPhoneNumber
|
64
|
+
><Email
|
65
|
+
>email to organizaiton, not the person</Email
|
66
|
+
><WebSite
|
67
|
+
>www.whatever.com</WebSite
|
68
|
+
><Employees
|
69
|
+
><Person
|
70
|
+
><IntegrationId
|
71
|
+
>123</IntegrationId
|
72
|
+
><FirstName
|
73
|
+
>Rune</FirstName
|
74
|
+
><LastName
|
75
|
+
>Rebellion</LastName
|
76
|
+
><DirectPhoneNumber
|
77
|
+
>+4611111</DirectPhoneNumber
|
78
|
+
><FaxPhoneNumber
|
79
|
+
>+4623234234234</FaxPhoneNumber
|
80
|
+
><MobilePhoneNumber
|
81
|
+
>+462321212</MobilePhoneNumber
|
82
|
+
><Email
|
83
|
+
>x@y.com</Email
|
84
|
+
><AlternativeEmail
|
85
|
+
>y@x.com</AlternativeEmail
|
86
|
+
><PostalAddress
|
87
|
+
><Street
|
88
|
+
>postal street</Street
|
89
|
+
><ZipCode
|
90
|
+
>226 48</ZipCode
|
91
|
+
><City
|
92
|
+
>LUND</City
|
93
|
+
></PostalAddress
|
94
|
+
><CurrentlyEmployed
|
95
|
+
>true</CurrentlyEmployed
|
96
|
+
></Person
|
97
|
+
></Employees
|
98
|
+
><CustomValues
|
99
|
+
><CustomValue
|
100
|
+
><Field
|
101
|
+
>external_url</Field
|
102
|
+
><Value
|
103
|
+
>http://something.com?key=6</Value
|
104
|
+
></CustomValue
|
105
|
+
></CustomValues
|
106
|
+
><Tags
|
107
|
+
><Tag
|
108
|
+
>Imported</Tag
|
109
|
+
></Tags
|
110
|
+
><ResponsibleCoworker
|
111
|
+
><Heading
|
112
|
+
>Evil Elvis</Heading
|
113
|
+
><IntegrationId
|
114
|
+
>666</IntegrationId
|
115
|
+
></ResponsibleCoworker
|
116
|
+
></Organization
|
117
|
+
></Organizations
|
118
|
+
><Deals
|
119
|
+
><Deal
|
120
|
+
><IntegrationId
|
121
|
+
>333</IntegrationId
|
122
|
+
><Name
|
123
|
+
>Feta affären</Name
|
124
|
+
><Probability
|
125
|
+
>50</Probability
|
126
|
+
><Value
|
127
|
+
>10000</Value
|
128
|
+
><OfferDate
|
129
|
+
>2013-12-01</OfferDate
|
130
|
+
><OrderDate
|
131
|
+
>2014-01-05</OrderDate
|
132
|
+
><Customer
|
133
|
+
><IntegrationId
|
134
|
+
>6</IntegrationId
|
135
|
+
><Heading
|
136
|
+
>Alfs Mjukvaruutveckling</Heading
|
137
|
+
></Customer
|
138
|
+
><ResponsibleCoworker
|
139
|
+
><Heading
|
140
|
+
>Evil Elvis</Heading
|
141
|
+
><IntegrationId
|
142
|
+
>666</IntegrationId
|
143
|
+
></ResponsibleCoworker
|
144
|
+
><CustomerContact
|
145
|
+
><IntegrationId
|
146
|
+
>123</IntegrationId
|
147
|
+
></CustomerContact
|
148
|
+
></Deal
|
149
|
+
></Deals
|
150
|
+
><Notes
|
151
|
+
/></GoImport
|
152
|
+
>
|
@@ -1,34 +1,192 @@
|
|
1
1
|
require 'fruit_to_lime'
|
2
2
|
|
3
|
-
class
|
4
|
-
|
3
|
+
class Exporter
|
4
|
+
# turns a row from the organization cssv file into
|
5
|
+
# a fruit_to_lime model that is used to generate xml
|
6
|
+
# Uses rootmodel to locate other related stuff such
|
7
|
+
# coworker
|
8
|
+
def to_organization(row, rootmodel)
|
5
9
|
organization = FruitToLime::Organization.new
|
10
|
+
# Integrationid is typically the id in the system that
|
11
|
+
# we are getting the csv from. Must be set to be able
|
12
|
+
# to import the same file more than once without
|
13
|
+
# creating duplicates
|
6
14
|
organization.integration_id = row['id']
|
7
15
|
organization.name = row['name']
|
16
|
+
# Just setting all basic properties to show whats available
|
17
|
+
# Remove or fix...
|
18
|
+
organization.organization_number = 'a number' # needs clean up, should have helpers for that in lib. Swedish format.
|
19
|
+
organization.email = 'email to organizaiton, not the person'
|
20
|
+
organization.web_site = 'www.whatever.com'
|
21
|
+
organization.central_phone_number = '0000' # needs clean up, should have helpers for that in lib. Default swedish format, convert to global format
|
22
|
+
|
23
|
+
# Addresses consists of several parts in Go.
|
24
|
+
# Lots of other systems have the address all in one
|
25
|
+
# line, to be able to match when importing it is
|
26
|
+
# way better to split the addresses
|
27
|
+
organization.with_visit_address do |address|
|
28
|
+
address.street = 'visit street'
|
29
|
+
address.zip_code = 'visit zip'
|
30
|
+
address.city = 'visit city'
|
31
|
+
end
|
32
|
+
|
33
|
+
# Another example of setting address using
|
34
|
+
# helper to split '226 48 LUND' into zip and city
|
35
|
+
organization.with_postal_address do |address|
|
36
|
+
address.street = 'postal street'
|
37
|
+
address.parse_zip_and_address_se '226 48 LUND'
|
38
|
+
end
|
39
|
+
|
40
|
+
# Responsible coworker is set by first locating
|
41
|
+
# it in the root model and then setting a reference
|
42
|
+
# to him/her
|
43
|
+
# We need to be able handle missing coworkers here
|
44
|
+
coworker = rootmodel.find_coworker_by_integration_id row['responsible_id']
|
45
|
+
organization.responsible_coworker = coworker.to_reference
|
46
|
+
|
47
|
+
# Tags are set and defined at the same place
|
48
|
+
# Setting a tag: Imported is useful for the user
|
49
|
+
organization.set_tag("Imported")
|
50
|
+
|
51
|
+
# When imported from web based ERP or similair that
|
52
|
+
# client will continue to use it can be useful to be
|
53
|
+
# able to link from Go to the same record in the ERP
|
54
|
+
# FOr instance Lime links
|
55
|
+
organization.set_custom_value("http://something.com?key=#{row['id']}", "external_url")
|
56
|
+
|
8
57
|
return organization
|
9
58
|
end
|
10
59
|
|
60
|
+
def to_coworker(row)
|
61
|
+
coworker = FruitToLime::Coworker.new
|
62
|
+
coworker.integration_id = row['id']
|
63
|
+
coworker.first_name = row['first_name']
|
64
|
+
coworker.last_name = row['last_name']
|
65
|
+
# Other optional attributes
|
66
|
+
coworker.email = 't@e.com'
|
67
|
+
coworker.direct_phone_number = '+46121212'
|
68
|
+
coworker.mobile_phone_number = '+46324234'
|
69
|
+
coworker.home_phone_number = '+46234234'
|
70
|
+
|
71
|
+
# Tags and custom fields are set the same
|
72
|
+
# way as on organizations
|
73
|
+
|
74
|
+
return coworker
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_person(row, rootmodel)
|
78
|
+
person = FruitToLime::Person.new
|
79
|
+
person.integration_id = row['id']
|
80
|
+
# Note that Go has separate first and last names
|
81
|
+
# Some splitting might be necessary
|
82
|
+
person.first_name = row['first_name']
|
83
|
+
person.last_name = row['last_name']
|
84
|
+
# other optional attributes
|
85
|
+
person.direct_phone_number = '+4611111'
|
86
|
+
person.fax_phone_number = '+4623234234234'
|
87
|
+
person.mobile_phone_number = '+462321212'
|
88
|
+
person.email = 'x@y.com'
|
89
|
+
person.alternative_email = 'y@x.com'
|
90
|
+
person.with_postal_address do |address|
|
91
|
+
address.street = 'postal street'
|
92
|
+
address.parse_zip_and_address_se '226 48 LUND'
|
93
|
+
end
|
94
|
+
|
95
|
+
# Tags and custom fields are set the same
|
96
|
+
# way as on organizations
|
97
|
+
|
98
|
+
# set employer connection
|
99
|
+
employer_id = row['employer_id']
|
100
|
+
employer = rootmodel.find_organization_by_integration_id employer_id
|
101
|
+
employer.add_employee person
|
102
|
+
end
|
103
|
+
|
104
|
+
def to_deal(row, rootmodel)
|
105
|
+
deal = FruitToLime::Deal.new
|
106
|
+
deal.integration_id = row['id']
|
107
|
+
deal.name = row['name']
|
108
|
+
# should be integer, same currency should be used in
|
109
|
+
# the system
|
110
|
+
deal.value = row['value']
|
111
|
+
|
112
|
+
# find stuff connected to deal
|
113
|
+
responsible = rootmodel.find_coworker_by_integration_id row['responsible_id']
|
114
|
+
organization = rootmodel.find_organization_by_integration_id row['customer_id']
|
115
|
+
person = organization.find_employee_by_integration_id row['customer_contact_id']
|
116
|
+
# connect the deal by references
|
117
|
+
deal.responsible_coworker = responsible.to_reference
|
118
|
+
deal.customer = organization.to_reference
|
119
|
+
deal.customer_contact = person.to_reference
|
120
|
+
|
121
|
+
# other optional attributes
|
122
|
+
deal.probability = 50 # should be between 0 - 100
|
123
|
+
deal.order_date = '2014-01-05' # Format ?
|
124
|
+
deal.offer_date = '2013-12-01' # Format ?
|
125
|
+
|
126
|
+
# status, how do we set this ?
|
127
|
+
|
128
|
+
return deal
|
129
|
+
end
|
130
|
+
|
11
131
|
def configure(model)
|
12
132
|
# add custom field to your model here. Custom fields can be
|
13
133
|
# added to organization, deal and person. Valid types are
|
14
134
|
# :String and :Link. If no type is specified :String is used
|
15
135
|
# as default.
|
136
|
+
model.settings.with_organization do |organization|
|
137
|
+
organization.set_custom_field( { :integrationid => 'external_url', :title => 'Link to external system', :type => :Link } )
|
138
|
+
end
|
139
|
+
end
|
16
140
|
|
17
|
-
|
18
|
-
|
141
|
+
def process_rows(file_name)
|
142
|
+
data = File.open(file_name, 'r').read.encode('UTF-8',"ISO-8859-1")
|
143
|
+
rows = FruitToLime::CsvHelper::text_to_hashes(data)
|
144
|
+
rows.each do |row|
|
145
|
+
yield row
|
19
146
|
end
|
20
147
|
end
|
21
148
|
|
22
|
-
def to_model(
|
149
|
+
def to_model(coworkers_filename, organization_filename, persons_filename, deals_filename)
|
150
|
+
# A rootmodel is used to represent all entitite/models
|
151
|
+
# that is exported
|
23
152
|
rootmodel = FruitToLime::RootModel.new
|
153
|
+
|
24
154
|
configure rootmodel
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
155
|
+
|
156
|
+
# coworkers
|
157
|
+
# start with these since they are referenced
|
158
|
+
# from everywhere....
|
159
|
+
if coworkers_filename != nil
|
160
|
+
process_rows coworkers_filename do |row|
|
161
|
+
rootmodel.add_coworker(to_coworker(row))
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# organizations
|
166
|
+
if organization_filename != nil
|
167
|
+
process_rows organization_filename do |row|
|
168
|
+
rootmodel.organizations.push(to_organization(row, rootmodel))
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# persons
|
173
|
+
# depends on organizations
|
174
|
+
if persons_filename != nil
|
175
|
+
process_rows persons_filename do |row|
|
176
|
+
# adds it self to the employer
|
177
|
+
to_person(row, rootmodel)
|
30
178
|
end
|
31
179
|
end
|
180
|
+
|
181
|
+
# deals
|
182
|
+
# deals can reference coworkers (responsible), organizations
|
183
|
+
# and persons (contact)
|
184
|
+
if deals_filename != nil
|
185
|
+
process_rows deals_filename do |row|
|
186
|
+
rootmodel.deals.push(to_deal(row, rootmodel))
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
32
190
|
return rootmodel
|
33
191
|
end
|
34
192
|
|
@@ -44,24 +202,29 @@ require "fileutils"
|
|
44
202
|
require 'pathname'
|
45
203
|
|
46
204
|
class Cli < Thor
|
47
|
-
desc "to_go
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
205
|
+
desc "to_go", "Generates a Go XML file"
|
206
|
+
method_option :output, :desc => "Path to file where xml will be output", :default => "export.xml", :type => :string
|
207
|
+
method_option :organizations, :desc => "Path to organization csv file", :type => :string
|
208
|
+
method_option :persons, :desc => "Path to persons csv file", :type => :string
|
209
|
+
method_option :coworkers, :desc => "Path to coworkers csv file", :type => :string
|
210
|
+
method_option :deals, :desc => "Path to deals csv file", :type => :string
|
211
|
+
def to_go
|
212
|
+
output = options.output
|
213
|
+
exporter = Exporter.new()
|
214
|
+
model = exporter.to_model(options.coworkers, options.organizations, options.persons, options.deals)
|
52
215
|
error = model.sanity_check
|
53
216
|
if error.empty?
|
54
217
|
validation_errors = model.validate
|
55
218
|
|
56
219
|
if validation_errors.empty?
|
57
|
-
model.serialize_to_file(
|
58
|
-
puts "
|
220
|
+
model.serialize_to_file(output)
|
221
|
+
puts "Generated Go XML file: '#{output}'."
|
59
222
|
else
|
60
|
-
puts "
|
223
|
+
puts "Could not generate file due to"
|
61
224
|
puts validation_errors
|
62
225
|
end
|
63
226
|
else
|
64
|
-
puts "
|
227
|
+
puts "Could not generate file due to"
|
65
228
|
puts error
|
66
229
|
end
|
67
230
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'tomodel'
|
3
|
+
|
4
|
+
describe 'Exporter' do
|
5
|
+
before(:all) do
|
6
|
+
exporter = Exporter.new
|
7
|
+
organizations_file = File.join(File.dirname(__FILE__), 'sample_data', 'organizations.csv')
|
8
|
+
coworkers_file = File.join(File.dirname(__FILE__), 'sample_data', 'coworkers.csv')
|
9
|
+
persons_file = File.join(File.dirname(__FILE__), 'sample_data', 'persons.csv')
|
10
|
+
deals_file = File.join(File.dirname(__FILE__), 'sample_data', 'deals.csv')
|
11
|
+
@model = exporter.to_model(coworkers_file, organizations_file, persons_file, deals_file)
|
12
|
+
end
|
13
|
+
it "will find something with a name" do
|
14
|
+
organization = @model.organizations[0]
|
15
|
+
organization.name.length.should > 0
|
16
|
+
end
|
17
|
+
end
|
@@ -1,2 +1,2 @@
|
|
1
|
-
id;name;
|
2
|
-
6;Alfs Mjukvaruutveckling
|
1
|
+
id;name;responsible_id
|
2
|
+
6;Alfs Mjukvaruutveckling;666
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fruit_to_lime
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0
|
4
|
+
version: 2.1.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2014-04-
|
14
|
+
date: 2014-04-23 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: iso_country_codes
|
@@ -135,7 +135,6 @@ executables:
|
|
135
135
|
extensions: []
|
136
136
|
extra_rdoc_files: []
|
137
137
|
files:
|
138
|
-
- lib/fruit_to_lime/address_helper.rb
|
139
138
|
- lib/fruit_to_lime/csv_helper.rb
|
140
139
|
- lib/fruit_to_lime/model/address.rb
|
141
140
|
- lib/fruit_to_lime/model/class_settings.rb
|
@@ -158,12 +157,16 @@ files:
|
|
158
157
|
- lib/fruit_to_lime.rb
|
159
158
|
- bin/fruit_to_lime
|
160
159
|
- templates/csv/convert.rb
|
160
|
+
- templates/csv/export.xml
|
161
161
|
- templates/csv/Gemfile
|
162
162
|
- templates/csv/lib/tomodel.rb
|
163
163
|
- templates/csv/Rakefile.rb
|
164
|
+
- templates/csv/spec/exporter_spec.rb
|
165
|
+
- templates/csv/spec/sample_data/coworkers.csv
|
166
|
+
- templates/csv/spec/sample_data/deals.csv
|
164
167
|
- templates/csv/spec/sample_data/organizations.csv
|
168
|
+
- templates/csv/spec/sample_data/persons.csv
|
165
169
|
- templates/csv/spec/spec_helper.rb
|
166
|
-
- templates/csv/spec/tomodel_spec.rb
|
167
170
|
- templates/excel/convert.rb
|
168
171
|
- templates/excel/Gemfile
|
169
172
|
- templates/excel/lib/tomodel.rb
|
@@ -177,8 +180,8 @@ files:
|
|
177
180
|
- templates/sqlserver/Rakefile.rb
|
178
181
|
- templates/sqlserver/spec/spec_helper.rb
|
179
182
|
- templates/sqlserver/spec/tomodel_spec.rb
|
183
|
+
- spec/address_spec.rb
|
180
184
|
- spec/custom_field_spec.rb
|
181
|
-
- spec/helpers/address_helper_spec.rb
|
182
185
|
- spec/helpers/csv_helper_spec.rb
|
183
186
|
- spec/helpers/roo_helper_spec.rb
|
184
187
|
- spec/helpers/serialize_helper_spec.rb
|
@@ -211,8 +214,8 @@ signing_key:
|
|
211
214
|
specification_version: 3
|
212
215
|
summary: Library to generate Lime Go xml import format
|
213
216
|
test_files:
|
217
|
+
- spec/address_spec.rb
|
214
218
|
- spec/custom_field_spec.rb
|
215
|
-
- spec/helpers/address_helper_spec.rb
|
216
219
|
- spec/helpers/csv_helper_spec.rb
|
217
220
|
- spec/helpers/roo_helper_spec.rb
|
218
221
|
- spec/helpers/serialize_helper_spec.rb
|
@@ -1,18 +0,0 @@
|
|
1
|
-
module FruitToLime
|
2
|
-
module AddressHelper
|
3
|
-
# parses a line like "226 48 LUND" into its corresponding
|
4
|
-
# zipcode and city properties on the address
|
5
|
-
def self.parse_line_to_zip_and_address_se(line, address)
|
6
|
-
matched_zipcode = /^\d{3}\s?\d{2}/.match(line)
|
7
|
-
if matched_zipcode && matched_zipcode.length == 1
|
8
|
-
address.zip_code = matched_zipcode[0].strip()
|
9
|
-
matched_city = /\D*$/.match(line)
|
10
|
-
if matched_city && matched_city.length == 1
|
11
|
-
address.city = matched_city[0].strip()
|
12
|
-
return address
|
13
|
-
end
|
14
|
-
end
|
15
|
-
return nil
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'tomodel'
|
3
|
-
|
4
|
-
describe 'ToModel' do
|
5
|
-
before(:all) do
|
6
|
-
toModel = ToModel.new
|
7
|
-
organizations_file =File.join(File.dirname(__FILE__), 'sample_data', 'organizations.csv')
|
8
|
-
@model = toModel.to_model(organizations_file)
|
9
|
-
end
|
10
|
-
it "will find something with a name" do
|
11
|
-
organization = @model.organizations[0]
|
12
|
-
organization.name.length.should > 0
|
13
|
-
end
|
14
|
-
end
|