Interchange6-Schema

 view release on metacpan or  search on metacpan

lib/Interchange6/Schema/Result/Product.pm  view on Meta::CPAN

Defaults to true.

=cut

column combine => {
    data_type     => "boolean",
    default_value => 1,
};

=head2 created

Date and time when this record was created returned as L<DateTime> object.
Value is auto-set on insert.

=cut

column created => {
    data_type     => "datetime",
    set_on_create => 1
};

=head2 last_modified

Date and time when this record was last modified returned as L<DateTime> object.
Value is auto-set on insert and update.

=cut

column last_modified => {
    data_type     => "datetime",
    set_on_create => 1,
    set_on_update => 1
};

=head1 RELATIONS

=head2 canonical

Type: belongs_to

Related object: L<Interchange6::Schema::Result::Product>

=cut

belongs_to
  canonical => "Interchange6::Schema::Result::Product",
  { 'foreign.sku' => 'self.canonical_sku' },
  { join_type => 'left' };

=head2 variants

Type: has_many

Related object: L<Interchange6::Schema::Result::Product>

=cut

has_many
  variants => "Interchange6::Schema::Result::Product",
  { "foreign.canonical_sku" => "self.sku" },
  { cascade_copy            => 0, cascade_delete => 0 };

=head2 cart_products

Type: has_many

Related object: L<Interchange6::Schema::Result::CartProduct>

=cut

has_many
  cart_products => "Interchange6::Schema::Result::CartProduct",
  "sku",
  { cascade_copy => 0, cascade_delete => 0 };

=head2 price_modifiers

Type: has_many

Related object: L<Interchange6::Schema::Result::PriceModifier>

=cut

has_many
  price_modifiers => "Interchange6::Schema::Result::PriceModifier",
  "sku";

=head2 inventory

Type: might_have

Related object: L<Interchange6::Schema::Result::Inventory>

=cut

might_have
  inventory => "Interchange6::Schema::Result::Inventory",
  "sku",
  { cascade_copy => 0, cascade_delete => 0 };

=head2 media_products

Type: has_many

Related object: L<Interchange6::Schema::Result::MediaProduct>

=cut

has_many
  media_products => "Interchange6::Schema::Result::MediaProduct",
  "sku",
  { cascade_copy => 0, cascade_delete => 0 };

=head2 merchandising_products

Type: has_many

Related object: L<Interchange6::Schema::Result::MerchandisingProduct>

=cut

has_many
  merchandising_products =>
  "Interchange6::Schema::Result::MerchandisingProduct",
  "sku",
  { cascade_copy => 0, cascade_delete => 0 };

=head2 merchandising_product_related

Type: has_many

Related object: L<Interchange6::Schema::Result::MerchandisingProduct>

=cut

has_many
  merchandising_product_related =>
  "Interchange6::Schema::Result::MerchandisingProduct",
  { "foreign.sku_related" => "self.sku" },
  { cascade_copy          => 0, cascade_delete => 0 };

=head2 navigation_products

Type: has_many

Related object: L<Interchange6::Schema::Result::NavigationProduct>

=cut

has_many
  navigation_products => "Interchange6::Schema::Result::NavigationProduct",
  "sku",
  { cascade_copy => 0, cascade_delete => 0 };

=head2 navigation

Type: many_to_many with navigation

=cut

many_to_many navigations => "navigation_products", "navigation";

=head2 orderlines

Type: has_many

Related object: L<Interchange6::Schema::Result::Orderline>

=cut

has_many
  orderlines => "Interchange6::Schema::Result::Orderline",
  "sku",
  { cascade_copy => 0, cascade_delete => 0 };

=head2 product_attributes

Type: has_many

Related object: L<Interchange6::Schema::Result::ProductAttribute>

=cut

has_many
  product_attributes => "Interchange6::Schema::Result::ProductAttribute",
  "sku",
  { cascade_copy => 0, cascade_delete => 0 };

=head2 media

Type: many_to_many with media

=cut

many_to_many media => "media_products", "media";

=head2 product_messages

Type: has_many

Related object: L<Interchange6::Schema::Result::ProductMessage>

=cut

has_many
  product_messages => "Interchange6::Schema::Result::ProductMessage",
  "sku", { cascade_copy => 0 };

=head2 messages

Type: many_to_many

Accessor to related Message results.

=cut

many_to_many messages => "product_messages", "message";

=head1 METHODS

Attribute methods are provided by the L<Interchange6::Schema::Base::Attribute> class.

=head2 insert

Override inherited method to call L</generate_uri> method in case L</name>
and L</sku> have been supplied as arguments but L</uri> has not.

=cut

sub insert {
    my ( $self, @args ) = @_;
    $self->generate_uri unless $self->uri;
    $self->next::method(@args);
    return $self;
}

=head2 update_price_modifiers

Called when L</price> is updated.

=cut

sub update_price_modifiers {
    my ( $self, $old_value, $new_value ) = @_;

    my $price_modifiers =
      $self->price_modifiers->search( { discount => { '!=' => undef } } );

    while ( my $result = $price_modifiers->next ) {
        $result->update(
            {
                price => sprintf( "%.2f",
                    $new_value - ( $new_value * $result->discount / 100 ) )
            }
        );
    }
}

=head2 generate_uri($attrs)

Called by L</new> if no uri is given as an argument.

The following steps are taken:

=over

1. Join C<< $self->name >> and C<< $self->uri >> with C<-> and stash

lib/Interchange6/Schema/Result/Product.pm  view on Meta::CPAN

=item Return Value: not defined

=back

Similar to L<DBIx::Class::Relationship::Base/set_$rel> except that this method DOES delete objects in the table on the right side of the relation.

=cut

sub set_reviews {
    my $self = shift;
    @_ > 0
      or $self->throw_exception(
        "set_reviews needs a list of objects or hashrefs" );
    my @to_set = ( ref( $_[0] ) eq 'ARRAY' ? @{ $_[0] } : @_ );
    $self->product_reviews->delete_all;
    $self->add_to_reviews( $_ ) for (@to_set);
}

=head2 quantity_in_stock

Returns undef if L<inventory_exempt> is true and otherwise returns the
quantity of the product in the inventory. For a product variant the
quantity returned is for the variant itself whereas for a canonical
(parent) product the quantity returned is the total for all variants.

If the query was constructed using
L<Interchange6::Schema::ResultSet::Product/with_quantity_in_stock> then
the cached value will be used rather than running a new query.

=cut

sub quantity_in_stock {
    my $self = shift;

    # if already loaded by resultset query then return that value
    return $self->get_column('quantity_in_stock')
      if $self->has_column_loaded('quantity_in_stock');

    my $quantity;
    my $variants = $self->variants;
    if ( $variants->has_rows ) {
        my $not_exempt = $variants->search( { inventory_exempt => 0 } );
        if ( $not_exempt->has_rows ) {
            $quantity = $not_exempt->search_related( 'inventory',
                { quantity => { '>' => 0 } } )->get_column('quantity')->sum;
        }
    }
    elsif ( ! $self->inventory_exempt ) {
        my $inventory = $self->inventory;
        $quantity = defined $inventory ? $self->inventory->quantity : 0;
    }
    return $quantity;
}

=head2 delete

Overload delete to force removal of any product reviews. Only parent products should have reviews so in the case of child products no attempt is made to delete reviews.

=cut

# FIXME: (SysPete) There ought to be a way to force this with cascade delete.

sub delete {
    my ( $self, @args ) = @_;
    my $guard = $self->result_source->schema->txn_scope_guard;
    $self->product_reviews->delete_all unless defined $self->canonical_sku;
    $self->next::method(@args);
    $guard->commit;
}

1;



( run in 0.568 second using v1.01-cache-2.11-cpan-39bf76dae61 )