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 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
- FruitToLime::AddressHelper::parse_line_to_zip_and_address_se(line, self)
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 :settings, :organizations, :coworkers, :deals, :notes, :import_coworker
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|
@@ -13,7 +13,8 @@ module FruitToLime
13
13
  @value = val
14
14
  end
15
15
  end
16
-
16
+
17
+ # @!visibility private
17
18
  def to_rexml(elem)
18
19
  element_name = serialize_name
19
20
  elem.add_element(element_name).text = @value.to_s.encode('utf-8')
@@ -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 = str }
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
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
  require 'fruit_to_lime'
3
3
 
4
- describe FruitToLime::AddressHelper do
4
+ describe FruitToLime::Address do
5
5
  describe "Parse line with swedish zip and city into zipcode" do
6
6
  let (:zip_code) {
7
7
  address = FruitToLime::Address.new
@@ -76,9 +76,9 @@ describe FruitToLime::SerializeHelper do
76
76
  addr.city = "Ankeborg"
77
77
  end
78
78
  p.currently_employed=true
79
- p.add_tag("tag:anka")
80
- p.add_tag("tag:Bj\u{00F6}rk")
81
- p.add_tag("tag:<Bj\u{00F6}rk>")
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.add_tag("tag:bibliotek")
131
- o.add_tag("tag:Bj\u{00F6}rk")
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.add_tag("tag:bibliotek")
21
- o.add_tag("tag:Bj\u{00F6}rk")
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 ToModel
4
- def to_organization(row)
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
- model.settings.with_deal do |deal|
18
- deal.set_custom_field( { :integrationid => 'discount_url', :title => 'Rabatt url', :type => :Link } )
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(organization_file_name)
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
- if organization_file_name != nil
26
- organization_file_data = File.open(organization_file_name, 'r').read.encode('UTF-8',"ISO-8859-1")
27
- rows = FruitToLime::CsvHelper::text_to_hashes(organization_file_data)
28
- rows.each do |row|
29
- rootmodel.organizations.push(to_organization(row))
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 ORGANIZATIONS FILE", "Exports xml to FILE using for ORGANIZATIONS csv file."
48
- def to_go(organizations, file = nil)
49
- file = 'export.xml' if file == nil
50
- toModel = ToModel.new()
51
- model = toModel.to_model(organizations)
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(file)
58
- puts "'#{organizations}' has been converted into '#{file}'."
220
+ model.serialize_to_file(output)
221
+ puts "Generated Go XML file: '#{output}'."
59
222
  else
60
- puts "'#{organizations}' could not be converted due to"
223
+ puts "Could not generate file due to"
61
224
  puts validation_errors
62
225
  end
63
226
  else
64
- puts "'#{organizations}' could not be converted due to"
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
@@ -0,0 +1,2 @@
1
+ id;first_name;last_name
2
+ 666;Evil;Elvis
@@ -0,0 +1,2 @@
1
+ id;name;value;responsible_id;customer_id;customer_contact_id
2
+ 333;Feta affären;10000;666;6;123
@@ -1,2 +1,2 @@
1
- id;name;
2
- 6;Alfs Mjukvaruutveckling
1
+ id;name;responsible_id
2
+ 6;Alfs Mjukvaruutveckling;666
@@ -0,0 +1,2 @@
1
+ id;employer_id;first_name;last_name
2
+ 123;6;Rune;Rebellion
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.1
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-10 00:00:00.000000000 Z
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