class MembershipsImport < Import include Imports::Rollback include Imports::Validations def kind "memberships" end def row_valid?(parsed_row) raise Import::RowError, "No Amount included in this row: #{parsed_row.row}" if parsed_row.unparsed_amount.blank? raise Import::RowError, "No Email included in this row: #{parsed_row.row}" unless attach_person(parsed_row).email.present? raise Import::RowError, "Please include a payment method in this row: #{parsed_row.row}" if parsed_row.payment_method.blank? valid_amount? parsed_row.unparsed_amount unless parsed_row.unparsed_amount.blank? valid_date? parsed_row.order_date unless parsed_row.order_date.blank? case detect_membership_type(parsed_row.membership_type).to_s when RollingMembershipType.to_s valid_date? parsed_row.start_date raise Import::RowError, "Please include a 'Period' for Rolling membership: #{parsed_row.row}" if parsed_row.period.blank? raise Import::RowError, "Please include a 'Duration' for Rolling membership: #{parsed_row.row}" if parsed_row.duration.blank? when SeasonalMembershipType.to_s valid_date? parsed_row.start_date valid_date? parsed_row.end_date end true end def new_membership_types self.import_rows.select('membership_name, membership_type, count(id) as member_count').where(membership_type_exists: false).group('membership_name') end def existing_membership_types self.import_rows.select('membership_name, membership_type, count(id) as member_count').where(membership_type_exists: true).group('membership_name') end def index_parsed_row(parsed_row) import_row = super import_row.membership_type = parsed_row.membership_type import_row.membership_name = parsed_row.membership_name import_row.membership_type_exists = find_membership_type(parsed_row).present? import_row end def process(parsed_row) row_valid?(parsed_row) person = create_person(parsed_row) member = create_member(person) membership_type = create_membership_type(parsed_row) order = create_order(parsed_row, person, member, membership_type) end def create_person(parsed_row) new_person = attach_person(parsed_row) existing_person = Person.first_or_initialize( {:email => new_person.email, :organization => self.organization} ) do |p| p.type = new_person.type p.subtype = new_person.subtype end if existing_person.new_record? existing_person.import = self else message(nil, parsed_row, existing_person, "#{existing_person.email} exists. Will merge records.") end existing_person.update_from_import(new_person) existing_person.skip_commit = true unless existing_person.save message = [] message << "#{parsed_row.email}: " unless parsed_row.email.blank? message << person.errors.full_messages.join(', ') raise Import::RowError, message.join('') end existing_person end def create_member(person) member = self.members.where(:person_id => person.id, :organization_id => self.organization_id).first unless member member = self.members.build member.email = person.email member.password = Devise.friendly_token.first(15) member.person = person member.organization = self.organization member.save! end member end def create_membership_type(parsed_row) membership_type = find_membership_type(parsed_row) unless membership_type klass = detect_membership_type(parsed_row.membership_type) membership_type = klass.new membership_type.import_id = self.id membership_type.name = parsed_row.membership_name membership_type.description = parsed_row.membership_name membership_type.organization = self.organization membership_type.price = parsed_row.amount case klass.to_s when SeasonalMembershipType.to_s membership_type.starts_at = DateTime.parse(parsed_row.start_date) membership_type.ends_at = DateTime.parse(parsed_row.end_date) when RollingMembershipType.to_s membership_type.starts_at = DateTime.parse(parsed_row.start_date) membership_type.duration = parsed_row.duration membership_type.period = parsed_row.period else raise Import::RowError, "Unknown membership type #{klass}" end membership_type.save(:validate => false) end membership_type end def find_membership_type(parsed_row) membership_type = MembershipType.where( :name => parsed_row.membership_name, :organization_id => self.organization.id ).first end def create_membership(parsed_row, member, membership_type) membership = self.memberships.build membership.organization = self.organization membership.membership_type = membership_type membership.member = member membership.price = parsed_row.amount membership.sold_price = parsed_row.amount membership.cart_price = parsed_row.amount membership.total_paid = parsed_row.amount membership.starts_at = DateTime.parse(parsed_row.start_date) case membership_type.type when SeasonalMembershipType.to_s membership.ends_at = DateTime.parse(parsed_row.end_date) when RollingMembershipType.to_s membership.ends_at = membership.starts_at + membership_type.duration_in_seconds else raise Import::RowError, "Failed to create a membership of type: #{membership_type}" end membership.save! membership end def existing_order(person, membership_type, payment_method) # lookup order ids: # for membership(s): # + of the same membership type # + with the same payment method # + and the same buyer existing_orders = ImportedOrder.joins(:items).where orders: { import_id: self.id, person_id: person.id, payment_method: payment_method }, items: { product_type: 'Membership', product_id: membership_type.id } order = existing_orders.last ImportedOrder.find(order.id) if order end def create_order(parsed_row, person, member, membership_type) order = existing_order(person, membership_type, parsed_row.payment_method) || ImportedOrder.new order.organization = self.organization order.payment_method = parsed_row.payment_method order.person = person order.details = "Imported by #{user.email} on #{I18n.l self.created_at_local_to_organization, :format => :date}" order.import = self product = create_membership(parsed_row, member, membership_type) item = Item.for(product, order) item.state = "settled" order.items << item order.skip_actions = true order.save unless parsed_row.order_date.blank? date_in_zone = DateTime.parse(parsed_row.order_date) order_date = date_in_zone - time_zone_parser.utc_offset.seconds order.update_attribute(:created_at, order_date) end order.create_generic_action(:memberships, self.id) order.actions.where(:type => 'GetAction').first.update_attribute(:occurred_at, order.created_at) order end def detect_membership_type(type) case type.to_s.downcase when /seasonal/ SeasonalMembershipType when /rolling/ RollingMembershipType else raise Import::RowError, "Unknown Membership Type: #{type}" end end def rollback rollback_orders rollback_actions rollback_memberships rollback_membership_types rollback_people end def rollback_members Member.where(:import_id => self.id).destroy_all end def rollback_memberships Membership.where(:import_id => self.id).destroy_all end def rollback_membership_types MembershipType.where(:import_id => self.id).destroy_all end def rollback_actions Action.where(:import_id => self.id).destroy_all end end