In case you haven't found an answer yet, I have a similar situation. This is what I did:
Do a form alter to remove the #ajax callback from the attribute fields. I just used a loop and set the #ajax callback to nothing.
Then override the #submit with my own custom submit.
foreach($form['attributes'] as $attribute => $v){
if(is_array($v['#ajax'])){
$form['attributes'][$attribute]['#ajax'] = '';
}
}
$form['#submit'][0] = 'MY_CUSTOM_add_to_cart_form_submit';
The reason for overriding the submit is because those ajax calls on attributes will refresh the form and set the hidden product_id field based on the attributes selected on the ajax call. Since that's not going to happen now, we need to find the correct product_id ourselves, before we send it to the normal submit handler.
The following works for my use case. It's pretty direct and some code was borrowed from the #ajax callback function we skipped.
function MY_CUSTOM_add_to_cart_form_submit($form, &$form_state) {
// easiest way I could find to get the product ids attached to this display was from the from id. After stripping the text, I explode with _ and I have an array of all the product ids.
$product_ids = explode('_', str_ireplace('commerce_cart_add_to_cart_form_', '', $form_state['values']['form_id']));
// Load all the active products intended for sale on this form.
$products = commerce_product_load_multiple($product_ids, array('status' => 1));
$attribute_names = $form_state['values']['attributes'];
// loop through all the product id / attribute combinations and save a matching product id when it's found.
foreach($products as $product_id => $product) {
$match = TRUE;
$product_wrapper = entity_metadata_wrapper('commerce_product', $product);
foreach($attribute_names as $k => $v) {
if($product_wrapper->{$k}->raw() != $v) {
$match = FALSE;
}
}
$product_match = $match ? $product_id : $product_match;
}
// save the matching product id
$form_state['values']['product_id'] = $product_match;
// call the original submit handler
commerce_cart_add_to_cart_form_submit($form, $form_state);
}
I don't know if this is the best way to do this, but it's working for me and seems pretty direct. In my case, it's limited to one product display and on set of products and a custom line item type. Because of this, I don't expect any problems with the rest of the store.
I hope this helps. If there is a better way I'd love the feedback.