fruit_to_lime 2.0.1 → 2.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|